Skip to content

[Revert] team invitation accept email-match check#1431

Merged
BilalG1 merged 1 commit into
devfrom
revert-team-invitation-email-check
May 14, 2026
Merged

[Revert] team invitation accept email-match check#1431
BilalG1 merged 1 commit into
devfrom
revert-team-invitation-email-check

Conversation

@BilalG1
Copy link
Copy Markdown
Collaborator

@BilalG1 BilalG1 commented May 13, 2026

Summary

Reverts the team-invitation accept email-match check added in #1365 in response to user friction. The check required the signed-in user to own the invited email as a verified contact channel before accepting, which rejected legitimate flows where the recipient hadn't verified the invited email on their account.

  • Drops the pre-claim validate hook in accept/verification-code-handler.tsx that compared the accepting user's verified channels to the invited email.
  • Drops the normalizeEmail(body.email) in send-code/route.tsx (only existed to make the now-removed compare case-insensitive).
  • Removes the four e2e tests that asserted the check (mismatch, does-not-burn, case-insensitive, happy-path).
  • Reverts items.test.ts invitee sign-up back to bare Auth.fastSignUp().

What's preserved

  • TeamInvitationEmailMismatch in packages/stack-shared/src/known-errors.tsx and its plumbing in client-interface.ts / client-app-impl.ts / client-app.ts — intentionally kept so the check can be reinstated in a focused follow-up without re-plumbing the SDK return types.
  • The TOCTOU fix from the same PR (atomic updateMany claim in route-handlers/verification-code-handler.tsx and its 5-parallel-redemption test) is unrelated and untouched.

Test plan

  • pnpm lint — clean (28/28)
  • pnpm --filter @stackframe/backend --filter @stackframe/e2e-tests typecheck — clean
  • Pre-existing dashboard typecheck failure on transaction-table.tsx:347 (refundEntries) reproduces on origin/dev — not caused by this PR
  • e2e team-invitations + items + otp sign-in suites

Summary by CodeRabbit

  • Bug Fixes

    • Simplified team invitation acceptance process by removing strict email matching requirements, allowing users to accept invitations more flexibly.
  • Tests

    • Updated team invitation tests to reflect simplified acceptance flow.

Review Change Stack

Removes the verified-email check added in #1365 from the team-invitation
accept handler and the corresponding send-code email normalization. The
check rejected accept attempts where the signed-in user didn't own the
invited email as a verified contact channel, which was causing user-
visible friction.

Leaves TeamInvitationEmailMismatch in known-errors and the SDK return-
type unions intact so the check can be reinstated without re-plumbing.

The verification-code TOCTOU fix from #1365 (atomic updateMany claim in
route-handlers/verification-code-handler.tsx) is unrelated and stays.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-auth-hosted-components Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-auth-mcp Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-backend Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-dashboard Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-demo Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-docs Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-preview-backend Ready Ready Preview, Comment May 13, 2026 10:22pm
stack-preview-dashboard Ready Ready Preview, Comment May 13, 2026 10:22pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This PR removes email normalization from team invitation sending and eliminates pre-claim email-matching validation from invitation acceptance. The invited email is no longer normalized or validated against the authenticated user's verified email, and corresponding e2e test protections are removed.

Changes

Email normalization and validation removal

Layer / File(s) Summary
Remove email validation from acceptance handler
apps/backend/src/app/api/latest/team-invitations/accept/verification-code-handler.tsx
The normalizeEmail import is removed and the validate step that enforced email-matching between the authenticated user and invited email is dropped. The handler configuration changes from accepting the invited email parameter to an empty object.
Remove email normalization from invitation sending
apps/backend/src/app/api/latest/team-invitations/send-code/route.tsx
The normalizeEmail import is removed and the invited email is passed directly to teamInvitationCodeHandler.sendCode without normalization.
Update e2e tests for removed email validation
apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts, apps/e2e/tests/backend/endpoints/api/v1/payments/items.test.ts
Test cases that verified email-mismatch rejection, code-burning behavior, case-insensitive matching, and the legitimate invitee flow are removed. A payment test is updated to call Auth.fastSignUp() without explicit email parameters.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • hexclave/stack-auth#1365: This PR removes the invitation email normalization and the validate(…{ email: invitedEmail }…) email-mismatch check that was added in the retrieved PR, directly undoing that feature.

Suggested reviewers

  • nams1570
  • N2D4

Poem

🐰 No more email normalization fuss,
Invitations now travel sans the normalize cuss,
Validation steps removed with a gentle hop,
The auth flow is cleaner, let the checking stop!
Tests updated too—a tidier way.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: reverting the team invitation accept email-match check that was introduced in PR #1365.
Description check ✅ Passed The description is comprehensive, covering the reason for revert, specific changes made, preserved components, and test plan status with clear explanations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch revert-team-invitation-email-check

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 13, 2026

Greptile Summary

This PR reverts the email-match validation introduced in #1365, removing the requirement that an accepting user own a verified contact channel matching the invited email address. The change is intentional and well-documented, trading a known security constraint for improved UX in legitimate flows where the recipient hadn't yet verified the invited address.

  • Drops the validate hook in verification-code-handler.tsx that compared the accepting user's verified channels to the invited email; the atomic TOCTOU fix from the same parent PR is preserved.
  • Removes normalizeEmail from send-code/route.tsx, so invitation codes now store the raw email address as supplied by the caller.
  • Deletes four e2e tests that covered the email-match scenarios (mismatch rejection, no-burn, case-insensitive match, happy path) and reverts the items.test.ts sign-up back to bare Auth.fastSignUp().

Confidence Score: 4/5

Safe to merge as an intentional, documented revert; the security tradeoff is explicitly acknowledged and a follow-up is planned.

The change is a deliberate revert with a well-described rationale. The only concern is that invitation codes will now store raw (non-normalized) email addresses, which a future email-match reimplementation must account for at compare time. No unintended logic changes are introduced.

When the email-match check is reinstated, send-code/route.tsx will need to decide whether to renormalize at write time or handle case-folding at compare time, given that codes created during this window may hold non-lowercase addresses.

Important Files Changed

Filename Overview
apps/backend/src/app/api/latest/team-invitations/accept/verification-code-handler.tsx Removes the pre-claim validate hook that enforced email ownership before accepting. The handler signature correctly drops the invitedEmail destructure; the TOCTOU atomic-claim fix is untouched.
apps/backend/src/app/api/latest/team-invitations/send-code/route.tsx Drops normalizeEmail wrapper around body.email; invitation codes will now store the raw (potentially mixed-case) email address supplied by the caller.
apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts Removes the four e2e tests that covered the email-match check (mismatch rejection, no-burn guarantee, case-insensitive normalization, happy-path). Remaining tests are untouched.
apps/e2e/tests/backend/endpoints/api/v1/payments/items.test.ts Reverts Auth.fastSignUp back to the bare (no email args) form, consistent with the removed email-ownership check.

Sequence Diagram

sequenceDiagram
    participant Inviter
    participant SendCode as send-code/route.tsx
    participant VC as verification-code-handler.tsx
    participant DB as Database

    Inviter->>SendCode: "POST /team-invitations/send-code {email, team_id}"
    Note over SendCode: normalizeEmail removed — raw email stored
    SendCode->>VC: "sendCode({method: {email: body.email}})"
    VC->>DB: "store verification code (method.email = raw)"
    VC-->>Inviter: invitation email sent

    Note over VC: validate() hook removed (no email-match check)

    participant AnyUser as Any Authenticated User
    AnyUser->>VC: "POST /team-invitations/accept {code}"
    VC->>VC: handler() — checks auth, restricted_reason, plan limits
    VC->>DB: add user to team
    VC-->>AnyUser: 200 OK
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/backend/src/app/api/latest/team-invitations/send-code/route.tsx:57
**Non-normalized email persisted in invitation codes**

With `normalizeEmail` removed, the raw `body.email` (e.g. `Alice@Example.com`) is now stored verbatim in the verification-code `method.email` field. When the PR description mentions reinstating the email-match check "in a friendlier form," any future implementation will need to normalize at compare time to handle case variations — or start normalizing again at write time. Invitations created during this window with a non-lowercase address will be harder to match without that note. Worth adding a code comment so the next author knows about the inconsistency.

Reviews (1): Last reviewed commit: "[Revert] team invitation accept email-ma..." | Re-trigger Greptile

@BilalG1 BilalG1 requested a review from N2D4 May 13, 2026 22:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/backend/src/app/api/latest/team-invitations/accept/verification-code-handler.tsx`:
- Line 72: The handler signature was changed to remove the invited-recipient
parameter (now `async handler(tenancy, {}, data, body, user)`), which drops
recipient binding and allows code redemption by any logged-in user; restore or
reintroduce the invited-email context in the handler signature and logic (e.g.,
accept an `invitedEmail` or `recipient` param from the claim path/body) and
enforce a binding in `handler` (in `verification-code-handler.tsx`) by checking
the invited email against the user's email or their unverified emails, or
attach/verify the invited email to the user during claim before granting
membership; ensure you only accept the code if the invited email matches (or is
attached/verified) to prevent transferred links being used by other accounts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60bdf199-4e88-465b-8ddf-8327185fc36a

📥 Commits

Reviewing files that changed from the base of the PR and between 748d708 and bcb441c.

📒 Files selected for processing (4)
  • apps/backend/src/app/api/latest/team-invitations/accept/verification-code-handler.tsx
  • apps/backend/src/app/api/latest/team-invitations/send-code/route.tsx
  • apps/e2e/tests/backend/endpoints/api/v1/payments/items.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts
💤 Files with no reviewable changes (1)
  • apps/e2e/tests/backend/endpoints/api/v1/team-invitations.test.ts

@github-actions github-actions Bot assigned BilalG1 and unassigned N2D4 May 14, 2026
@BilalG1 BilalG1 merged commit 9885052 into dev May 14, 2026
37 of 39 checks passed
@BilalG1 BilalG1 deleted the revert-team-invitation-email-check branch May 14, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants