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

Step-by-Step Resolution

Step 1 — Enumerate what the session actually stored

Different storage locations have different lifetimes and different clearing mechanisms:

Where an authenticated session leaves tracesEach storage location survives logout by default and needs a different mechanism to clear, which is why a single measure rarely covers everything.Survives logoutCleared byHTTP disk cacheClear-Site-Data "cache"Back/forward cachenot clearable, disqualify insteadCache StorageClear-Site-Data "storage"localStorageClear-Site-Data "storage"CookiesusuallyClear-Site-Data "cookies", or expiry
Five places a session leaves something behind

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.

What a logout can and cannot reachThe server can invalidate its own session and ask the browser to clear storage, but the in-memory suspended page is outside the reach of any header on the logout response.BrowserServerPOST /logoutinvalidate the session200 + Clear-Site-Datadrops cache, cookies, storagesuspended page in memory remains
Two of the three copies are reachable

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
What survives when the logout request never happensClear-Site-Data depends on a logout that completes; header discipline applies to every response regardless of how the session ends.Rely on Clear-Site-Data24responses tab closed, nothing clearedprivate, no-cache24responses stored, unusable without a sessionno-store on the payload0responsesmeasured across one authenticated session flow
Sensitive responses remaining after an abandoned session

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 401 or a redirect to login can itself be stored heuristically and served after a new sign-in, producing a loop. Mark them no-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.


Back to no-cache vs no-store