Skip to content

fix: keep the session cookies when a refresh fails transiently - #37

Merged
Bccorb merged 2 commits into
mainfrom
fix/refresh-failures-keep-session
Nov 5, 2026
Merged

Bccorb merged 2 commits into
mainfrom
fix/refresh-failures-keep-session

Conversation

@Bccorb

@Bccorb Bccorb commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Parity with fells-code/seamless-auth-go#22 and fells-code/seamless-auth-server#273 for cookie transport. Today every refresh failure signs the browser out, including an auth API outage or a 5xx during a deploy.

Cookies are now cleared only when the auth API answers the refresh with 401, or the refresh cookie cannot be read; those keep today's answers (silent refresh 401 Refresh failed, POST /refresh 401 invalid_refresh_token).

Case Silent refresh and cookie POST /refresh Cookies
Transport error, 2xx with no session, a session that fails verification, a waiter timing out 502 upstream_unavailable kept
Any other non-2xx (503, 429, 403, 500) status and body pass through (upstream_error for a non-JSON body) kept
401 from the API, unreadable cookie unchanged cleared

_silent_refresh returns the rotated session, a _RefreshFailed(reason, reply), or None with no refresh cookie, replacing the old string sentinel. In-flight sharing, the cookie-only 5 second window (successful rotations only), bearer refresh, logout and the post-enrollment refresh are unchanged.

c087de1 adds tests/test_refresh_failures.py alone (38 cases across silent refresh, cookie POST /refresh, FastAPI and Django); 26 fail on main. Client code that treated any refresh failure as signed out may now see 502, 503 or 429; the README's "How it runs" section has the table.

ruff, ruff format, mypy strict, check-manifest.sh pass; pytest 634 passed. Not covered: Python does not forward Retry-After (Rust does on bearer refresh).

…nswers 401

Covers silent refresh and cookie-transport POST /refresh, in the core and
through the FastAPI and Django bindings: a transport error, a 2xx with no
session or an unverifiable one, and a waiter timing out answer 502
upstream_unavailable; any other non-2xx passes through; only a 401 or an
unreadable refresh cookie clears the cookies.
In cookie transport, silent refresh and POST /refresh cleared every session
cookie on any refresh failure, so an auth API outage or a 503 during a
deploy signed every browser out. Now only a 401 from the auth API, or a
refresh cookie that cannot be read, ends the session. A transport error, a
2xx with no session or one that fails verification, and a waiter timing out
on another rotation answer 502 upstream_unavailable; any other non-2xx
passes its status and body through. The cookies are kept in each case.
Matches seamless-auth-go.
@Bccorb
Bccorb merged commit 586b933 into main Nov 5, 2026
7 checks passed
@github-actions github-actions Bot mentioned this pull request Nov 5, 2026
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.

1 participant