Frontend Labs
⋯

Part VII — Client-side storage and encryption

43. Cookies in depth: attributes, HttpOnly/Secure/SameSite

Cookies are the oldest browser storage mechanism and the only one automatically sent with every matching HTTP request — which is exactly what makes them right for session tokens and wrong for anything large or non-auth-related (they add latency to every single request, including ones for images and static assets).

document.cookie = "theme=dark; max-age=31536000; path=/; SameSite=Lax";
// document.cookie is a deceptively simple-looking API for a genuinely
// weird format: reading it returns ALL cookies as one semicolon-joined
// string; writing it sets exactly ONE cookie per call.

Security-relevant attributes, set by the server (never fully trustworthy if set only from JS, since JS-set cookies can't set HttpOnly on themselves):

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict; Path=/

HttpOnly   -> JS (document.cookie) CANNOT read this cookie at all — the single
              most important XSS mitigation for session tokens: even a full
              XSS payload cannot exfiltrate an HttpOnly cookie via JS.
Secure     -> only sent over HTTPS, never plaintext HTTP.
SameSite=Strict -> never sent on cross-site requests, even top-level navigation
                     from an external link (strongest CSRF protection, but
                     breaks "click an email link and stay logged in" flows).
SameSite=Lax    -> sent on top-level cross-site navigation (clicking a link)
                     but NOT on cross-site subrequests (images, fetches,
                     iframes) — the modern browser DEFAULT, a reasonable
                     CSRF/usability balance.
SameSite=None   -> sent on all cross-site requests; REQUIRES Secure — needed
                     for legitimate third-party embeds (payment widgets,
                     SSO iframes), but is exactly the setting that enables
                     cross-site tracking, which is why browsers are
                     progressively restricting third-party cookies entirely.

War story. An app stored its auth token in localStorage "for easy JS access" instead of an HttpOnly cookie. A single stored-XSS bug in an unrelated comment-rendering feature let an attacker's script read localStorage.authToken directly and exfiltrate it to an external server — full account takeover from one XSS bug, because nothing stood between the attacker's injected script and the token. An HttpOnly cookie would have made that specific token structurally unreadable by the same injected script, containing the blast radius to whatever the XSS could do live in the page, not a portable stolen credential.

Generated from real-life-JS-guide.md · 8 Oct 2026 16:36