Skip to content

Show team invitations in the app; invite email reads less like phishing - #170

Merged
ralyodio merged 1 commit into
mainfrom
worktree-invite-inapp
Oct 12, 2026
Merged

ralyodio merged 1 commit into
mainfrom
worktree-invite-inapp

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Why

Anthony invited preshy@profullstack.com and "he didn't get it". Prod facts (2026-10-12):

  • 4 invites to preshy since 9/28, all team.invited … sent: true; Resend shows today's (01a12f48…) as delivered to profullstack.com's MX (Forward Email). Sending domain verified + DKIM.
  • preshy already has a verified account (signed up 9/28) — but the emailed link was the only way to accept, so a filtered or unread email meant no way in.
  • The email read like phishing: subject "Join anthony@profullstack.com workspace on OutreachGraph", body "anthony@profullstack.com invited you to join anthony@profullstack.com workspace".

What

  • GET /api/v1/me/invitations: pending invitations matching the signed-in user's verified address (excludes orgs already joined, expired and revoked ones).
  • POST /api/v1/me/invitations/:id/accept: accept without a token; re-pins the session like the link does; audited with via: in_app. Unverified addresses and other people's ids → 400 "not valid".
  • App shell banner: "X invited you to their team · Join".
  • Email: an email-named org becomes "their team"; subject "<inviter> invited you to OutreachGraph"; Reply-To is the inviter; it tells existing users the invite is waiting in their inbox; there's an "Accept the invitation" anchor and the raw link stays.

Tests

  • team.test.ts: 4 new tests (existing account accepts in-app; unverified refused; someone else's refused; expired/revoked not offered). 15/15 pass.
  • app.test.ts 73/73, packages/email 39/39, root typecheck + apps/web tsc clean, prettier clean.

🤖 Generated with Claude Code

… like phishing

An invitation could only be accepted through the emailed link. preshy@ was
invited four times; Resend reports every one delivered to the profullstack.com
MX, yet none was seen — and he already has a verified account. The email was
the single point of failure.

- GET /api/v1/me/invitations lists pending invitations matching the signed-in
  user's verified address; POST /api/v1/me/invitations/:id/accept joins without
  a token. Unverified addresses and other people's ids are refused.
- The app shell shows a "X invited you to their team · Join" banner.
- The email no longer says "a@x.com invited you to join a@x.com workspace":
  an unnamed (email-named) org reads "their team", the subject names the
  inviter, Reply-To is the inviter, and it says existing accounts will find the
  invitation on sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ralyodio
ralyodio merged commit 9030aba into main Oct 12, 2026
4 checks passed
@ralyodio ralyodio mentioned this pull request Oct 12, 2026
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.

1 participant