Repository navigation
feat: JWT mode with access and refresh tokens - #6
Merged
Merged
Conversation
createAuth({ jwt: { secret, issuer?, accessTtlMs?, reuseGraceMs? } }): login
returns an HS256 access JWT (sub, org, sid) and an opaque single-use refresh
token; refresh() rotates it, and a spent token reused after the grace window
ends the session. Every request still checks the session and re-reads the
user, so logout and disabling apply at once. verifyAccessToken() checks a
JWT without storage. Secret rotation, no dependency (node:crypto). 1.1.0.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BA5Vx77ihDsLiZpyg5duJV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Before: login returned one opaque session token, which the client sent on every request until it expired.
After: with
createAuth({ …, jwt: { secret } }), login returns two tokens:sub,org,sidandexp(15 minutes by default);refresh({ refreshToken })returns a new pair and spends the old refresh token. If a spent refresh token comes back after a short grace window (15 s, for two tabs refreshing at once), the whole session ends, because that only happens when the token was copied. Withoutjwt, nothing changes.The rules stay intact:
verifyAccessToken()checks a JWT's signature without touching storage, for workers or other services.algis never trusted, soalg: noneis refused.The api uses this for its new access/refresh flow. Version 1.1.0.
Type
Checklist
main)npm run typecheckpassesnpm test: 98 passed, 0 failed. The JWT flows run on both the memory and Redis stores and cover tampering, alg none, foreign secret, rotation, refresh rotation, reuse detection, logout by either token, password change, disabled user, expiry and the no-raw-token check.🤖 Generated with Claude Code
https://claude.ai/code/session_01BA5Vx77ihDsLiZpyg5duJV
Generated by Claude Code