[Revert] team invitation accept email-match check#1431
Conversation
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis 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. ChangesEmail normalization and validation removal
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis 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.
Confidence Score: 4/5Safe 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
Sequence DiagramsequenceDiagram
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
Prompt To Fix All With AIFix 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 |
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
apps/backend/src/app/api/latest/team-invitations/accept/verification-code-handler.tsxapps/backend/src/app/api/latest/team-invitations/send-code/route.tsxapps/e2e/tests/backend/endpoints/api/v1/payments/items.test.tsapps/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
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.
validatehook inaccept/verification-code-handler.tsxthat compared the accepting user's verified channels to the invited email.normalizeEmail(body.email)insend-code/route.tsx(only existed to make the now-removed compare case-insensitive).items.test.tsinvitee sign-up back to bareAuth.fastSignUp().What's preserved
TeamInvitationEmailMismatchinpackages/stack-shared/src/known-errors.tsxand its plumbing inclient-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.updateManyclaim inroute-handlers/verification-code-handler.tsxand 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— cleantransaction-table.tsx:347(refundEntries) reproduces onorigin/dev— not caused by this PRSummary by CodeRabbit
Bug Fixes
Tests