Skip to content

fix: logout + Back no longer views/interacts with the dashboard (hard-nav + bfcache guard) - #14

Merged
xdroberto merged 3 commits into
developfrom
fix/dashboard-bfcache-logout
Jul 8, 2026
Merged

fix: logout + Back no longer views/interacts with the dashboard (hard-nav + bfcache guard)#14
xdroberto merged 3 commits into
developfrom
fix/dashboard-bfcache-logout

Conversation

@xdroberto

@xdroberto xdroberto commented Jul 8, 2026

Copy link
Copy Markdown
Owner

The bug (found in prod during release testing)

After logout, pressing Back re-showed the dashboard — and, as Roberto found on a second pass, it was not just viewable but interactive while logged out. The session is revoked server-side, so this is a defense-in-depth + UX gap, not an auth bypass — but it must not happen.

Root cause — two layers

  1. Client soft-nav on logout (the interaction). The logout handlers did await signOut(); router.push("/login"). router.push is a soft navigation: it leaves the dashboard SPA and Next's client Router Cache (prefetched authenticated RSC) alive. Pressing Back restored the still-mounted dashboard, and cached soft navigations rendered other dashboard pages with no server round-trip — so the dead session was never re-checked. That's why a logged-out user could browse/interact.
  2. Browser bfcache (the view). Dashboard pages are dynamically rendered and Next owns their Cache-Control (no-cache, never no-store — the only directive that disables bfcache). Neither next.config headers() nor the edge proxy can override a dynamic route's Cache-Control (verified empirically), so Back could restore a stale render from the browser's back/forward cache.

Fix — two parts

  1. Hard navigation on logout: window.location.href = "/login" instead of router.push — a full load tears down the SPA and discards the Router Cache. (Dropped the now-unused useRouter.)
  2. BfcacheGuard in the dashboard layout: reloads any page restored from bfcache (pageshow + persisted); the reload re-hits the auth check. MDN's documented pattern.

Together with the edge proxy (no cookie → /login), Back after logout now lands on /login through every path. Scoped to /dashboard; the static landing stays cacheable (Phase 3 LCP work untouched).

Test plan

  • e2e 12/12. The auth flow test now presses Back after logout and asserts /login — it reproduced the bug on the soft-nav version and passes on the fix. A security test pins that a logged-out reload of the dashboard lands on /login.
  • biome · next build (31 routes) green.
  • Please re-verify by hand in a real browser (log in → log out → Back → try to click around): must land on /login. Headless bfcache is unreliable to trigger and window.location.reload can't be spied in Chromium, so the browser-bfcache path is hand-verified.

Base is develop (recreated from main — the release merge auto-deleted it). Promote develop→main to ship.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PA9EzergAZ12Dy1QBqx5kp

xdroberto and others added 2 commits July 8, 2026 13:03
…ow a stale dashboard

After logout, pressing Back restored the authenticated dashboard from the
browser's back/forward cache (bfcache). The session is already invalidated
server-side (any interaction 401s -> redirect), so this is a defense-in-depth
+ UX gap, not an auth bypass.

Root cause: dashboard pages are dynamically rendered (cookies/headers) and Next
owns their Cache-Control — it serves `no-cache, must-revalidate`, not
`no-store`. Only `no-store` disables bfcache in Chromium/Firefox, and neither
next.config headers() nor the edge proxy can override a dynamic route's
Cache-Control (verified empirically — both are dropped/replaced).

Fix: a client BfcacheGuard in the dashboard layout reloads any page restored
from bfcache (`pageshow` with `persisted`); the reload re-hits the auth check
and a logged-out visitor is redirected to /login (MDN's documented pattern for
this exact problem). Scoped to the dashboard; the static marketing/landing
stays cacheable (Phase 3 LCP work untouched).

e2e: pins that a logged-out reload of the dashboard lands on /login (real
bfcache Back is verified manually — headless bfcache is unreliable to trigger
and window.location.reload can't be spied in Chromium).
Verified: biome, next build (31 routes), full e2e 12/12.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PA9EzergAZ12Dy1QBqx5kp
…shboard

Follow-up to the BfcacheGuard: that alone was insufficient. The logout handlers
did `await signOut(); router.push("/login")` — a SOFT (client-side) navigation.
A soft nav leaves the dashboard SPA and Next's client Router Cache alive, so
after logout, Back restored the still-mounted dashboard and its prefetched
authenticated RSC — the logged-out user could not just VIEW it but navigate and
interact via cached soft navigations (no server round-trip, so the dead session
was never re-checked).

Fix: `window.location.href = "/login"` — a hard navigation that tears down the
SPA and discards the Router Cache. Combined with the BfcacheGuard (browser
bfcache restore → reload) and the edge proxy (no cookie → /login), Back after
logout now lands on /login through every path. Dropped the now-unused useRouter.

e2e: the auth flow test now presses Back after logout and asserts /login (it
reproduced the bug on the soft-nav version). Full suite 12/12; build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PA9EzergAZ12Dy1QBqx5kp
@xdroberto xdroberto changed the title fix(dashboard): logout + Back no longer shows a stale dashboard (bfcache guard) fix: logout + Back no longer views/interacts with the dashboard (hard-nav + bfcache guard) Jul 8, 2026
Nova Analytics v1.0.0. Aligns the package version (inherited 2.2.0 from the
arhamkhnz template) with the v1.0.0 release tag. Version field only — no
dependency or lockfile-format changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PA9EzergAZ12Dy1QBqx5kp
@xdroberto
xdroberto merged commit 6178f19 into develop Jul 8, 2026
3 checks passed
@xdroberto
xdroberto deleted the fix/dashboard-bfcache-logout branch July 8, 2026 20:42
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