fix(auth): tolerate refresh-token rotation races

Parallel refresh requests from a single client (multi-tab SPA, mobile tab restore)
tripped reuse-detection and logged users out every few hours. Track rotation
provenance via new rotated_at + replaced_by_token_hash columns and accept revoked-
token reuse only inside a configurable grace window with a chain that reaches a
live, non-logout link. Scope the rotate UPDATE with revoked_at IS NULL so a
concurrent logout or admin revoke fails the racing refresh instead of handing the
user a fresh access token.

Closes #120
This commit is contained in:
neon
2026-05-28 04:48:09 +00:00
parent 2161c9d1af
commit df20b6f8e6
11 changed files with 10808 additions and 43 deletions
+1
View File
@@ -17,6 +17,7 @@ export const authConfig = registerAs('auth', () => ({
jwtExpiresIn: process.env.JWT_EXPIRES_IN ?? '15m',
jwtRefreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN ?? '7d',
setupBootstrapToken: process.env.SETUP_BOOTSTRAP_TOKEN ?? '',
refreshRotationGraceMs: parsePositiveInteger(process.env.AUTH_REFRESH_ROTATION_GRACE_MS, 30_000),
}));
export const storageConfig = registerAs('storage', () => ({