Skip to content

fix: auto-merge Google email alias accounts at login#1861

Merged
bokelley merged 6 commits into
mainfrom
bokelley/fix-stripe-membership-sync
Apr 3, 2026
Merged

fix: auto-merge Google email alias accounts at login#1861
bokelley merged 6 commits into
mainfrom
bokelley/fix-stripe-membership-sync

Conversation

@bokelley

@bokelley bokelley commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Auto-merge duplicate Google alias accounts at login: Users with both gmail.com and googlemail.com accounts (same inbox) are automatically merged when they log in. Uses atomic alias-claim to prevent race conditions on concurrent logins.
  • Admin link-customer endpoint syncs membership_tier and stripe_subscription_id: Previously these fields were missed when manually linking a Stripe customer, leaving orgs without proper tier entitlements.
  • Email normalization utilities: normalizeEmail() and getGoogleEmailAliases() handle all Google domain variants (gmail.com, googlemail.com, googlemail.co.uk, gmail.co.uk).

Context

Triggered by escalation #195/#196: Lina Georg paid $250 for Professional membership via twiegle@gmail.com but logs in with twiegle@googlemail.com (common in Germany where googlemail.com was the default). Her login account showed no subscription.

Root cause: WorkOS created two separate user accounts for what Google treats as the same mailbox.

How it works

  1. At OAuth callback, getGoogleEmailAliases() checks all Google domain variants
  2. If a duplicate account exists, atomically claims the alias via INSERT ... ON CONFLICT DO NOTHING (prevents concurrent-login race)
  3. Merges the duplicate into the current session user via existing mergeUsers() transaction
  4. Dashboard shows green "Accounts merged" banner on success, or falls back to manual merge banner on failure

Test plan

  • email-domain.test.ts — 14 tests covering all alias variants
  • TypeScript compiles clean
  • All pre-commit checks pass (451 schemas, 826 MDX files, docs nav, etc.)
  • Verify Lina's next login triggers auto-merge and grants certification access

🤖 Generated with Claude Code

Users in countries where googlemail.com was the default (e.g. Germany)
can end up with two accounts for the same mailbox. This caused a member
who paid via gmail.com to see no subscription when logging in with
googlemail.com.

- Detect all Google domain aliases (gmail.com, googlemail.com,
  googlemail.co.uk, gmail.co.uk) at login via getGoogleEmailAliases()
- Auto-merge the duplicate into the current session user, with
  atomic alias-claim to prevent concurrent-login race conditions
- Show a green "Accounts merged" banner on success, fall back to
  manual merge banner if the auto-merge fails
- Admin link-customer endpoint now syncs membership_tier and
  stripe_subscription_id alongside other subscription fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread server/tests/unit/email-domain.test.ts Fixed
bokelley and others added 5 commits April 3, 2026 16:07
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add UNIQUE(LOWER(email)) index on user_email_aliases to prevent two
  users from claiming the same alias concurrently
- Roll back alias claim if mergeUsers fails so retry works on next login
- Broaden NOT EXISTS check to skip emails claimed by any user
- Remove unconfirmed gmail.co.uk from alias set

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit 5b8fbcc into main Apr 3, 2026
13 checks passed
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