CodeOath
← All posts
Auth & Security60 min total · 19 parts

OAuth 2.0 and JWT Explained: How "Login with Google" Actually Works

Contents — Part 13 of 19: Token Storage: Where Should Tokens Live in the Browser
Part 13 of 19 · ~2 min

Token Storage: Where Should Tokens Live in the Browser

Once your backend has tokens, where the browser keeps anything it needs (a session identifier, or a token for a pure SPA architecture) has real security consequences, and the two common options trade off different risks.

StorageReadable by JavaScriptVulnerable toSent automatically on requests
localStorage / sessionStorageYesXSS — any injected script can read and exfiltrate the tokenNo — must be attached manually to each request
httpOnly cookieNoCSRF — the browser attaches it automatically, including to requests a malicious page triggersYes — automatically, by the browser

Storing a token in localStorage means a single successful XSS injection (a dependency with a vulnerability, an unescaped user-generated field rendered as HTML) can read it directly and exfiltrate it to an attacker's server — localStorage has no concept of restricting which JavaScript on the page can access it. An httpOnly cookie can't be read by any JavaScript at all, including an attacker's injected script, which closes that specific hole — but because the browser now attaches it automatically to any request to that domain, it reopens the door to CSRF (covered in detail below) unless the cookie is also paired with SameSite and CSRF-token protections.

The practical recommendation most production systems converge on: keep the actual access and refresh tokens server-side entirely (in an httpOnly, Secure, SameSite=Lax or Strict session cookie, or in a server-side session store keyed by an opaque cookie value), and never hand a long-lived credential to client-side JavaScript at all. A pure SPA with no backend of its own is the one case that's forced to hold tokens in the browser directly — and it's exactly the case where the token storage trade-off above needs the most deliberate thought.