Skip to content

fix(web): propagate session invalidation to /api/auth/session#1219

Merged
msukkari merged 3 commits into
mainfrom
msukkari/fix-session-invalidation
May 22, 2026
Merged

fix(web): propagate session invalidation to /api/auth/session#1219
msukkari merged 3 commits into
mainfrom
msukkari/fix-session-invalidation

Conversation

@msukkari
Copy link
Copy Markdown
Contributor

@msukkari msukkari commented May 22, 2026

  • bump sessionVersion when user signs out
  • add sessionVersion check in jwt callback
  • remove redundant sessionVersion check in auth method, which now uses sessionVersion check in the jwt callback

Ensures that:

  • logging out invalidates all previous session tokens (even if they were captured outside the browser)
  • ensures that calls to /api/auth/session are covered by session version check

Summary by CodeRabbit

Bug Fixes

  • Session invalidation events—including logout, user deletion, and removal from an organization—are now properly reflected in real-time session status checks.
  • Previously issued authentication tokens are now correctly invalidated upon logout, preventing their reuse in subsequent API requests.

Review Change Stack

msukkari and others added 2 commits May 21, 2026 18:54
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>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Walkthrough

Session invalidation for signout and user deletion is synchronized with JWT validation by incrementing sessionVersion on signOut, checking that version in the jwt callback (with lazy issuerUrl migration), and simplifying the auth helper to delegate enforcement to NextAuth.

Changes

Session Invalidation Sync

Layer / File(s) Summary
JWT callback session validity enforcement
packages/web/src/auth.ts
JWT callback fetches the current user and sessionVersion, returning null to invalidate tokens when the user no longer exists or the stored sessionVersion mismatches the token's version on non-login requests; lazy issuerUrl backfill is integrated into the same database fetch.
SignOut session version increment
packages/web/src/auth.ts
SignOut increments the user's sessionVersion in the database before recording the audit event, invalidating all previously-issued JWTs on their next validation.
Auth helper simplification
packages/web/src/auth.ts
Auth helper is simplified to a per-request memoized call to nextAuthResult.auth(), removing redundant sessionVersion checks since the jwt callback now handles validation.
Changelog entry
CHANGELOG.md
Added Unreleased Fixed entry documenting that session invalidation events (signout, user deletion, org removal) now sync with the /api/auth/session endpoint.

Sequence Diagram

sequenceDiagram
  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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main change: fixing session invalidation propagation to the /api/auth/session endpoint, which is the core problem addressed in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch msukkari/fix-session-invalidation

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
CHANGELOG.md (1)

14-15: 💤 Low value

Add 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3851c66 and de019df.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • packages/web/src/auth.ts

Comment thread packages/web/src/auth.ts
Comment thread packages/web/src/auth.ts Outdated
Comment thread packages/web/src/auth.ts Outdated
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>
@msukkari msukkari merged commit 8292882 into main May 22, 2026
10 checks passed
@msukkari msukkari deleted the msukkari/fix-session-invalidation branch May 22, 2026 02:56
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.

2 participants