Skip to content

Commit 5494630

Browse files
LEANDERANTONYclaude
andcommitted
Fix: align access cookie lifetime to refresh cookie (Codex P1 finding)
The auth_cookies module set ACCESS_TOKEN_MAX_AGE to 7 days while REFRESH_TOKEN_MAX_AGE was 30 days. The docstring on those constants claims "the access token mirrors [refresh] so a quiet tab doesn't lose only half its credentials" — but the actual values didn't mirror. Real-world failure mode: * Session restore (resolve_authenticated_context) requires BOTH cookies present. * A user returning after 7+ days (but within 30) has a valid refresh cookie but a purged access cookie. * Restore rejects the half-credentialed pair and forces a fresh OAuth re-login, defeating the "stay signed in" UX the 30-day refresh window was meant to deliver. Fix matches the docstring's stated intent: both cookies live for 30 days. The COOKIE's max_age governs browser purge time, NOT the JWT's validity — Supabase rotates the access JWT on every restore using the still-valid refresh JWT, so the inside-the-cookie token being temporally stale is fine and expected. Codex P1 finding on PR #2 (May 2026). Auth-test suite (14 tests) still green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 48a6f6b commit 5494630

1 file changed

Lines changed: 14 additions & 3 deletions

File tree

backend/services/auth_cookies.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@
2222
REFRESH_TOKEN_COOKIE = "ja_refresh_token"
2323

2424
# Sliding expiries. Refresh token controls "stay signed in" duration; the
25-
# access token mirrors it so a quiet tab doesn't lose only half its
26-
# credentials. AuthService rotates tokens on restore, and the router
25+
# access cookie mirrors it so a quiet tab doesn't lose only half its
26+
# credentials. AuthService rotates tokens on restore (Supabase mints a
27+
# fresh access JWT from the still-valid refresh JWT), and the router
2728
# re-issues both cookies on every restore call.
28-
_ACCESS_TOKEN_MAX_AGE_SECONDS = 60 * 60 * 24 * 7 # 7 days
29+
#
30+
# The COOKIE's max_age controls when the browser purges the cookie;
31+
# the JWT inside has its own short-lived exp claim (Supabase rotates
32+
# on restore). Keeping both cookies at the same max_age means a user
33+
# returning within the refresh window always has both cookies present
34+
# for the restore call to use — without that, a 7+ day quiet user
35+
# would lose their access cookie while the refresh cookie is still
36+
# valid and `resolve_authenticated_context` would reject the
37+
# half-credentialed restore, forcing an unnecessary re-login (Codex
38+
# P1 finding on PR #2, May 2026).
39+
_ACCESS_TOKEN_MAX_AGE_SECONDS = 60 * 60 * 24 * 30 # 30 days
2940
_REFRESH_TOKEN_MAX_AGE_SECONDS = 60 * 60 * 24 * 30 # 30 days
3041

3142

0 commit comments

Comments
 (0)