Skip to content

fix(auth): CF Access logout revocation, refresh-family binding, safe logout redirect#1193

Merged
ToddHebebrand merged 1 commit into
mainfrom
fix/cf-access-token-revocation
Jun 10, 2026
Merged

fix(auth): CF Access logout revocation, refresh-family binding, safe logout redirect#1193
ToddHebebrand merged 1 commit into
mainfrom
fix/cf-access-token-revocation

Conversation

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

Root cause: Verification of the v0.69.0..main Codex review confirmed three gaps in the Cloudflare Access SSO paths added in #1058 — the CF cohort had strictly weaker token-theft protection than password users:

  1. GET /cf-access-logout (cfAccessRedirectLogin.ts:230) was synchronous and only called clearRefreshTokenCookie — no revokeAllUserTokens, no jti revocation. After "Sign out", an exfiltrated access token stayed valid to expiry and the 7-day refresh token remained fully usable. Header.tsx routes CF logout exclusively through this endpoint and skips apiLogout().
  2. Both CF token-mint paths (cfAccessLogin.ts:164, cfAccessRedirectLogin.ts:160) called createTokenPair with no refreshFam, so CF-minted tokens fall into the /refresh handler's legacy skip path and the family-revocation reuse-detection (RFC 9700 §4.13.2) never fires for them — exactly the invariant refreshTokenFamily.ts's docstring warns about.
  3. The logout redirect origin was built from the attacker-controllable Host header (open redirect off the Breeze origin).

Fix:

  • Logout resolves the refresh cookie, verifies the JWT (signature-checked, so a forged cookie can't trigger revocation for another user), then revokeAllUserTokens(sub) + revokeRefreshTokenJti(jti) — mirroring POST /logout. Missing/invalid cookie or Redis failure still clears + 302s (no 500).
  • Both mint paths now do mintRefreshTokenFamilycreateTokenPair(..., { refreshFam })bindRefreshJtiToFamily, same as /login.
  • Redirect origin comes from DASHBOARD_URL || PUBLIC_APP_URL (the established pattern in login.ts/password.ts); https-pinned Host fallback only when neither is set.
  • Docs now instruct covering /api/v1/auth/cf-access-login + /cf-access-logout in the Access application and warn against an /api/* bypass swallowing them.

Tests: 11 new tests (logout revocation incl. no-cookie/invalid-cookie/Redis-failure paths, family binding on both mint paths incl. the MFA temp-token short-circuit, spoofed-Host redirect cases). cfAccessRedirectLogin.test.ts + cfAccessLogin.test.ts: 32/32 pass; login.test.ts + helpers.test.ts regression: 11/11 pass.

🤖 Generated with Claude Code

…g-derived logout redirect

Three gaps in the Cloudflare Access SSO paths (#1058 follow-up) left CF
users with weaker token-theft protection than password users:

- GET /cf-access-logout only cleared the cookie; access tokens stayed valid
  to expiry and the 7-day refresh token remained fully usable. Now resolves
  the refresh cookie, verifies it, and calls revokeAllUserTokens + revokes
  the refresh jti, mirroring POST /logout. Best-effort: missing/invalid
  cookie or Redis errors still clear + redirect.
- Both CF token-mint paths (cfAccessLogin middleware + cf-access-login
  redirect route) called createTokenPair without a refresh-token family,
  so stolen-token reuse detection (family revocation on rotation replay)
  was silently disabled for the CF cohort. Both now mint + bind a family,
  same as /login.
- The logout redirect origin was built from the attacker-controllable Host
  header (open redirect). Now derived from DASHBOARD_URL/PUBLIC_APP_URL,
  with an https-pinned Host fallback only when neither is configured.
- Docs: cloudflare-access-trust.mdx now lists cf-access-login/logout as
  paths the Access application must cover.

32/32 tests pass across both touched test files (11 new), plus login/helpers
regression run 11/11.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying breeze with  Cloudflare Pages  Cloudflare Pages

Latest commit: e53a304
Status: ✅  Deploy successful!
Preview URL: https://6ce4c809.breeze-9te.pages.dev
Branch Preview URL: https://fix-cf-access-token-revocati.breeze-9te.pages.dev

View logs

@ToddHebebrand ToddHebebrand merged commit 8ac1d69 into main Jun 10, 2026
32 checks passed
@ToddHebebrand ToddHebebrand deleted the fix/cf-access-token-revocation branch June 10, 2026 15:52
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