Skip to content

fix: auto-link users by domain, reject stale sessions#2138

Merged
bokelley merged 2 commits into
mainfrom
bokelley/fix-member-profile-auth
Apr 14, 2026
Merged

fix: auto-link users by domain, reject stale sessions#2138
bokelley merged 2 commits into
mainfrom
bokelley/fix-member-profile-auth

Conversation

@bokelley

@bokelley bokelley commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Escalation #231 (ResponsiveAds member-profile auth failure).

Root cause: Matthew Snyder had a duplicate WorkOS account that was cleaned up, but stale session JWTs from the deleted account pass local validation and hit "not a member" errors downstream.

Two fixes:

  • Auto-link by verified domain (membership-db.ts, member-profiles.ts, http.ts): When /api/me or member-profile routes return no WorkOS org memberships, check if the user's email domain matches a verified domain on an org with active subscription. If so, create the WorkOS membership automatically. Covers users who authenticated but were never added to their org.

  • Stale session rejection (auth.ts): On session cache miss, verify the authenticated user exists in the local users table. If not found, kill the session and force re-login. Catches deleted/merged WorkOS accounts with unexpired JWTs. Fails open on DB errors.

Also ran:

  • POST /api/admin/users/sync-users — synced 1392 users, confirmed ghost account gone from WorkOS
  • POST /api/admin/users/sync-workos — synced 1071 orgs, removed 33 stale memberships

Test plan

  • Verify TypeScript compiles clean
  • Unit tests pass (597/597)
  • Test login flow still works after auth.ts change
  • Verify member-profile page loads for logged-in member
  • Confirm stale session cookie gets rejected and user is redirected to login

🤖 Generated with Claude Code

bokelley and others added 2 commits April 14, 2026 14:22
…p missing

When a user authenticates but has no WorkOS organization memberships,
check whether their email domain matches a verified domain on an org
with an active subscription. If so, create the membership in WorkOS
automatically. This closes a gap where subscriptions were provisioned
without the corresponding WorkOS membership (e.g. ResponsiveAds
escalation #231).

Applied to /api/me, GET/POST/PUT /api/me/member-profile routes.
Includes integration tests for the autoLinkByVerifiedDomain function.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WorkOS session JWTs are validated locally without an API call, so a
deleted/merged user's JWT can remain valid until expiry. This caused
"not a member" errors when users authenticated with stale sessions
from cleaned-up duplicate accounts.

On session cache miss, verify the user exists in the local users table.
If not found, kill the session and force re-login. Fails open on DB
errors to avoid blocking auth during outages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bokelley bokelley changed the title fix: auto-link users to orgs by verified domain fix: auto-link users by domain, reject stale sessions Apr 14, 2026
@bokelley bokelley merged commit f2122b6 into main Apr 14, 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