Skip to content

fix: drop sessions carrying an expired access token - #16

Merged
cuzzlor merged 2 commits into
mainfrom
fix/expired-session-token-wedge
Aug 16, 2026
Merged

cuzzlor merged 2 commits into
mainfrom
fix/expired-session-token-wedge

Conversation

@cuzzlor

@cuzzlor cuzzlor commented Aug 15, 2026 •

Copy link
Copy Markdown
Collaborator

Stack 3/3 — stacked on #15 (base branch fix/login-unhandled-rejection); the diff shows only this PR's commits. Merging the full stack releases v2.1.0 — this PR includes the minor version bump, so the publish workflow ships both fixes when it lands on main.

Problem

The session cookie can outlive the access token it stores (e.g. a 1h cookie holding a token Entra issued with a shorter lifetime, or any visit after token expiry but before cookie expiry). When that happens:

  1. copySessionJwtToBearerHeader keeps copying the expired token to the authorization header, where it fails bearer verification on the resource server → 401/FORBIDDEN.
  2. The header's presence suppresses the interactive re-login redirect that apps typically gate on the header being absent (the pattern in this package's README).

The browser is wedged on 401s until the cookie expires or the user manually logs out.

Fix

Decode the token's exp claim — plain base64 payload decode, no signature verification, which remains the resource server's job — and when it has expired, drop the session (req.session = null) and skip the copy. The login middleware then re-runs on the same request, giving the user a transparent SSO redirect instead of a dead end. Unparsable tokens still pass through untouched for downstream bearer verification to judge, exactly as before.

Also bumps the package version to 2.1.0 as the top of the stack.

Testing

Added src/copy-session-jwt-to-bearer-header.spec.ts:

  • unexpired token is copied to the header (unchanged behaviour)
  • expired token → session dropped, nothing copied
  • unparsable token passes through
  • existing authorization header and unauthenticated sessions untouched

npm run lint, npm run check-types, and npm test all pass, plus npm run build and npm run audit on the assembled stack.

🤖 Generated with Claude Code

@cuzzlor

cuzzlor commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

CI here fails only on the audit step — advisories pre-dating this branch (main fails identically). #17 clears them; update this branch after it merges and CI should go green.

@cuzzlor
cuzzlor requested a review from robdmoore August 15, 2026 09:42
@cuzzlor
cuzzlor force-pushed the fix/expired-session-token-wedge branch from 13112ba to cc1477e Compare August 15, 2026 09:43
@cuzzlor
cuzzlor changed the base branch from main to fix/login-unhandled-rejection August 15, 2026 09:43
Base automatically changed from fix/login-unhandled-rejection to main August 16, 2026 09:59
cuzzlor added a commit that referenced this pull request Aug 16, 2026
`npm audit fix` resolves 23 of the 24 advisories accumulated since the
last release (vite, shell-quote, qs, fast-uri, launch-editor, etc. —
all transitive devDependencies; nothing shipped changes).

The remaining low-severity advisory (GHSA-g7r4-m6w7-qqqr, esbuild
0.27.3–0.28.0 dev-server file read on Windows) has no in-range fix via
tsx/vite yet, so it gets an .nsprc exception with removal notes —
esbuild is only used here as a build/test transform, never as a dev
server. The stale uuid exception (fixed by the update) is removed.

Unblocks CI for #15 and #16, which fail on the audit step for
advisories predating those branches.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
cuzzlor and others added 2 commits August 16, 2026 17:59
The session cookie can outlive the access token it stores. When that
happens, copySessionJwtToBearerHeader keeps copying the expired token
to the authorization header, where it fails bearer verification on the
resource server — while its presence suppresses the interactive
re-login redirect apps typically gate on the header being absent. The
browser is wedged on 401s until the cookie expires or the user
manually logs out.

Decode the token's exp claim (no signature verification — that remains
the resource server's job) and, when it has expired, drop the session
and skip the copy so the login middleware re-runs on the same request.
Unparsable tokens still pass through untouched for downstream bearer
verification to judge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Releases the login-handler crash fix and the expired-session fix together.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cuzzlor
cuzzlor force-pushed the fix/expired-session-token-wedge branch from cc1477e to e687e7c Compare August 16, 2026 09:59
@cuzzlor
cuzzlor merged commit abacbad into main Aug 16, 2026
1 check 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.

2 participants