fix(web): propagate session invalidation to /api/auth/session#1219
Conversation
NextAuth's stock /api/auth/session route decodes the JWT and returns
the user record to the client without consulting Sourcebot's database.
Three release-acceptance scenarios depended on the endpoint reporting
"logged out" after invalidation:
- AUTHN-004: replayed cookie after signout.
- AUTHN-006: replayed cookie after user is removed from org.
- AUTHN-011: replayed cookie after user is deleted.
The wrapped auth() at the application layer was already cross-checking
sessionVersion and the User row's existence on every withAuth call, so
protected resources correctly returned 401 in all three cases. But
because /api/auth/session never went through that wrapper, the
endpoint continued to leak a positive "you're signed in" answer.
Two changes close the gap:
1. events.signOut now increments User.sessionVersion before writing
the audit log, mirroring invalidateAllSessionsForUser. This is
what AUTHN-004 specifically needed.
2. The jwt callback now performs a single User.findUnique on every
non-login request, returning null when the row is missing
(AUTHN-011) or sessionVersion has been bumped since the JWT was
minted (AUTHN-004 / AUTHN-006). When the callback returns null,
@auth/core (a) reports the session as logged out from
/api/auth/session, (b) skips the rolling-session cookie refresh,
and (c) clears the cookie from the browser via Set-Cookie.
The same query also batches the existing lazy issuerUrl migration,
so the new check costs one User.findUnique per request (with the
existing accounts findMany folded into the same query, net query
count is unchanged or lower).
With the jwt callback now responsible for the invalidation check, the
duplicate cross-check that lived in the wrapped auth() resolver has
been removed. The wrapper is now just a React cache() boundary around
nextAuthResult.auth().
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughSession invalidation for signout and user deletion is synchronized with JWT validation by incrementing ChangesSession Invalidation Sync
Sequence DiagramsequenceDiagram
participant NextAuth
participant jwt_callback
participant Database
NextAuth->>jwt_callback: call jwt callback with token
jwt_callback->>Database: fetch user(sessionVersion) + accounts where issuerUrl IS NULL for token.userId
alt user not found
jwt_callback->>NextAuth: return null (invalidate)
else user found
alt non-login && token.sessionVersion != db.sessionVersion
jwt_callback->>NextAuth: return null (invalidate)
else
jwt_callback->>Database: update accounts.issuerUrl where available (lazy migrate)
jwt_callback->>NextAuth: return token (valid)
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
🚥 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
CHANGELOG.md (1)
14-15: 💤 Low valueAdd blank line before next version header.
The new entry should be followed by a blank line before the
## [4.17.2]header to maintain consistent formatting with the rest of the changelog.📝 Proposed formatting fix
- Fixed issue where session invalidation (signout, user deletion, removal from org) was not reflected by `/api/auth/session`. [`#1219`](https://github.com/sourcebot-dev/sourcebot/pull/1219) + ## [4.17.2] - 2026-05-16🤖 Prompt for 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. In `@CHANGELOG.md` around lines 14 - 15, Add a single blank line between the release entry ending with "Fixed issue where session invalidation (signout, user deletion, removal from org) was not reflected by `/api/auth/session`. [`#1219`](https://github.com/sourcebot-dev/sourcebot/pull/1219)" and the following version header "## [4.17.2] - 2026-05-16" so the new entry is separated by one empty line and matches the changelog's consistent formatting.
🤖 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.
Nitpick comments:
In `@CHANGELOG.md`:
- Around line 14-15: Add a single blank line between the release entry ending
with "Fixed issue where session invalidation (signout, user deletion, removal
from org) was not reflected by `/api/auth/session`.
[`#1219`](https://github.com/sourcebot-dev/sourcebot/pull/1219)" and the following
version header "## [4.17.2] - 2026-05-16" so the new entry is separated by one
empty line and matches the changelog's consistent formatting.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4f61856c-dab2-4a9f-b5e4-7f92b96b2474
📒 Files selected for processing (2)
CHANGELOG.mdpackages/web/src/auth.ts
Slightly easier to read the cross-check condition when the JWT-side value isn't sharing a line with the && and the inequality. No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sessionVersionwhen user signs outsessionVersioncheck injwtcallbackauthmethod, which now usessessionVersioncheck in thejwtcallbackEnsures that:
/api/auth/sessionare covered by session version checkSummary by CodeRabbit
Bug Fixes