Clearing Cached Responses After Logout
Problem Statement
A user logs out on a shared machine. The session is invalidated at the server, the cookie is gone, and pressing the back button still displays their account page — rendered from a copy the browser stored while they were signed in. Logout is a server-side event; the browser’s storage is unaffected by it unless it is told otherwise.
Prerequisite Concepts
no-cachevsno-store: when to use each — the difference between storing and reusing.- Public vs private cache scope — which tier holds a copy of an authenticated response.
- no-store and the browser back/forward cache — the in-memory copy that behaves differently from all of these.
Step-by-Step Resolution
Step 1 — Enumerate what the session actually stored
Different storage locations have different lifetimes and different clearing mechanisms:
Step 2 — Send Clear-Site-Data on the logout response
The logout endpoint is the one point where the server can ask the browser to clean up:
POST /logout
HTTP/2 200
Clear-Site-Data: "cache", "cookies", "storage"
Cache-Control: no-store
Two details matter. The directives are quoted strings, and an unquoted value is ignored silently. And the header must be on a response the browser actually receives — a logout that redirects should carry it on the redirect response itself, not only on the destination, since the destination may be a different origin.
Step 3 — Verify the back button
This is the check that catches the case a cache clear does not cover:
# Confirm the authenticated document was never storable in the first place
curl -sI -H "Cookie: sid=$SESSION" https://example.com/account \
| grep -iE 'cache-control|clear-site-data'
Then, in a browser: sign in, visit an authenticated page, sign out, and press back. A page that reappears with its content intact is being restored from memory, and no header on the logout response will remove it. The fix is either to disqualify those pages from restore, or to handle the restore event and re-check the session:
window.addEventListener("pageshow", async (event) => {
if (!event.persisted) return;
const res = await fetch("/api/session", { cache: "no-store" });
if (!res.ok) location.replace("/login");
});
Step 4 — Remove the need to clear
Clearing is a cleanup step that depends on the logout actually happening. A user who closes the tab, loses connectivity, or has the browser terminated never sends the request, and everything stored remains. The durable protection is to store nothing worth clearing:
GET /api/account/statements.json
Cache-Control: no-store
GET /account/statements
Cache-Control: private, no-cache
Step 5 — Re-check with every new authenticated route
Storage hygiene decays. A route added later inherits whatever default the server applies, and defaults are written for the public part of a site. A single check in the release pipeline covers it:
for path in /account /account/statements /api/account/statements.json; do
printf '%-36s ' "$path"
curl -sI -H "Cookie: sid=$SESSION" "https://staging.example.com$path" \
| awk -F': ' '/[Cc]ache-[Cc]ontrol/{print $2}'
done
Anything authenticated returning a public directive, or no directive at all, is a finding.
Expected Output / Verification
A correctly configured flow shows no sensitive response marked storable, a logout response carrying the clearing header, and a back navigation that lands on the login page rather than on cached content:
/account private, no-cache
/account/statements private, no-cache
/api/account/statements.json no-store
POST /logout no-store + Clear-Site-Data: "cache", "cookies", "storage"
back after logout redirected to /login
Edge Cases
- Clear-Site-Data on a cross-origin redirect. The header applies to the origin of the response carrying it. A logout that immediately redirects to an identity provider may clear nothing on your own origin unless the header is on the first response.
- Partial support. Not every browser implements every directive. Treat it as defence in depth rather than as the control.
- Service worker caches. A worker that cached authenticated responses keeps them under its own storage. Clearing storage removes them, but the worker must also not re-populate them on the next visit.
- Shared computers with several profiles. Clearing affects the profile that made the request only, which is usually what is wanted but is worth being explicit about in any policy discussion.
- A logout that fails. If the request errors, nothing is cleared and the session may still be valid client-side. Clearing locally before confirming the server response leaves a worse state than doing neither.
- Cached error pages from an expired session. A
401or a redirect to login can itself be stored heuristically and served after a new sign-in, producing a loop. Mark themno-store.
Frequently Asked Questions
Does logging out clear the browser cache?
No. Ending a session invalidates a credential on the server; it has no effect on anything the browser already stored. Cached responses from before the logout remain on disk until they expire or are evicted.
What does Clear-Site-Data actually remove?
Depending on the directives sent, it can clear cookies, the HTTP cache, and origin-scoped storage such as Cache Storage, localStorage and IndexedDB for the requesting origin. Support is good in Chromium-based browsers and less complete elsewhere, so it is a mitigation rather than a guarantee.
Why can the back button still show the old page?
Because a back navigation may be answered from the back/forward cache, which holds a constructed page in memory rather than a response in the HTTP cache. Clearing the cache does not remove it; only disqualifying the page or handling the restore event does.
Is Clear-Site-Data a substitute for no-store?
No. It is a cleanup after the fact and depends on the browser honouring it and on the logout request actually being made. A sensitive response that was never stored needs no cleanup, which is why the header discipline matters more.
Related
- When to use no-store for sensitive API responses covers the directive that makes clearing unnecessary.
- no-store and the browser back/forward cache explains the in-memory copy that survives a cache clear.
- Cache storage, eviction and capacity describes how long an uncleared entry can realistically persist.
Back to no-cache vs no-store