Skip to content

fix(bd-jv5u083l): renewal verdict deadline unwedges expiry logout#270

Merged
shikokuchuo merged 3 commits into
mainfrom
feature/bd-jv5u083l-expiry-refresh-only
Jun 11, 2026
Merged

fix(bd-jv5u083l): renewal verdict deadline unwedges expiry logout#270
shikokuchuo merged 3 commits into
mainfrom
feature/bd-jv5u083l-expiry-refresh-only

Conversation

@shikokuchuo

@shikokuchuo shikokuchuo commented Jun 10, 2026

Copy link
Copy Markdown
Member

Background

How the hub client manages session expiry today (useAuth):

  1. On page load, GET /auth/me checks whether the auth cookie is valid; a 401 shows the login screen.
  2. Fifteen minutes before the token expires, the client asks Google One Tap for a fresh credential ("silent renewal") and exchanges it for a new cookie via POST /auth/refresh.
  3. At the expiry time itself, the client re-checks /auth/me. A definitive 401 logs the user out (with a "session expired" message); a network error keeps the session and re-checks every 60 seconds — so offline editing survives expiry, and the dead session is adjudicated as soon as the hub is reachable again.
  4. While a renewal is in flight, the client sets an isRefreshing flag so that concurrent triggers coalesce, the tab-refocus check stands down, and the expiry re-check waits for the renewal's verdict instead of logging the user out underneath it.

The bug

Step 4 assumed the identity provider always answers. It doesn't: if the One Tap prompt never fires (script blocked by an ad blocker, FedCM / third-party-cookie policies, unregistered origin — we've observed gsi/status 403 in dev), neither the success nor the error callback ever runs, and isRefreshing stays true for the lifetime of the tab. Everything gated on that flag then silently dies:

  • the at-expiry re-check loops forever "waiting for a verdict" — the user is never logged out at expiry;
  • the refocus check early-returns — no recovery when the tab regains focus;
  • every later triggerRefresh() is a no-op — no retry, ever.

So in exactly the environments where silent renewal can't work, the client neither renews nor logs out, until a full page reload or a websocket drop.

The fix

A 30-second verdict deadline on the in-flight renewal. If the provider hasn't settled by then, the renewal counts as failed and the flag clears, so the expiry re-check reaches its verdict normally: 401 → logout, network error → keep waiting.

The regression test mounts a session, lets the renewal trigger, and never settles it; it fails on main (the session survives expiry) and passes with the fix.

Comment thread hub-client/src/hooks/useAuth.ts Outdated
@shikokuchuo shikokuchuo marked this pull request as draft June 10, 2026 14:49
When the IdP never calls back (GIS blocked / FedCM), isRefreshing stayed
true for the tab's lifetime: the at-exp re-check rescheduled forever
without a verdict and refocus/retry were disabled. A 30s deadline now
settles the flag so the expiry check can log out (or keep waiting on
network errors).
@shikokuchuo shikokuchuo force-pushed the feature/bd-jv5u083l-expiry-refresh-only branch from 9b5422f to 9cd290e Compare June 11, 2026 09:58
@shikokuchuo shikokuchuo changed the title fix(bd-jv5u083l): expiry timer refresh-only; probe owns logout fix(bd-jv5u083l): renewal verdict deadline unwedges expiry logout Jun 11, 2026
@shikokuchuo shikokuchuo marked this pull request as ready for review June 11, 2026 10:11
…ilure path

refreshTimer/expiryTimer were only used inside the schedule effect —
effect-local variables replace the refs and the redundant top-of-effect
clears (cleanup always runs before re-run). The verdict deadline and
onError shared a settle+disable sequence, now abandonRenewal. No
behavior change; existing tests unchanged.
@shikokuchuo shikokuchuo merged commit 1aab641 into main Jun 11, 2026
4 of 5 checks passed
@shikokuchuo shikokuchuo deleted the feature/bd-jv5u083l-expiry-refresh-only branch June 11, 2026 10:44
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.

2 participants