HttpOnly cookies are generally safer when the architecture supports them because JavaScript cannot read them directly. localStorage is simpler, but it exposes tokens to any script running in the page, which makes XSS a direct credential-theft path.
Why browser storage choice changes the attack path
For single-page apps, the key distinction is not convenience but where the credential can be reached at runtime. Tokens in localStorage are readable by any script that runs in the page, so a successful XSS issue can become immediate token theft. HttpOnly cookies are not readable by JavaScript, which removes that direct exfiltration path.
That safety gain is real, but it comes with architectural conditions. Cookie-based auth shifts more of the burden onto browser cookie behavior, CSRF defenses, same-site settings, and server-side session handling. If the application cannot support those controls cleanly, the better storage choice on paper can still produce a weak implementation in practice.
What each option implies for session security
localStorage is usually treated as a bearer-token container. That means any script with execution in the origin can access the token, whether the script is first-party code, a compromised dependency, or injected payload. In practice, the storage layer becomes part of your secret-protection boundary, which is why XSS severity increases when access tokens live there.
HttpOnly cookies change the model. The browser sends them automatically, but client-side code cannot read them directly. That reduces token theft from script execution, yet it does not remove session risk. If an attacker can trigger authenticated requests, abuse a logged-in browser session, or exploit weak cookie scope and CSRF controls, the session can still be misused even when the cookie value stays hidden.
For SPAs that rely on APIs, the safest pattern is usually to keep short-lived access semantics, rotate or reissue credentials carefully, and make sure the browser storage choice matches the rest of the auth design. A secure storage container cannot compensate for a weak token lifetime, permissive CORS design, or a front end that is already exposed to unsafe script execution.
What usually decides the right answer in practice
The decision usually turns on whether you can support cookie-based browser sessions without breaking the app's routing, API calls, and logout behavior. If you can, HttpOnly cookies generally reduce the blast radius of XSS because the token is no longer directly script-readable. If you cannot, localStorage may be easier to implement, but the application must then treat every script execution path as a potential credential exposure path.
Modern guidance also treats authentication as a system property, not a storage preference. A strong SPA implementation usually combines a browser-safe session mechanism with secure token issuance, narrow privilege, short lifetimes, and rigorous XSS prevention. For identity and browser-session design, NIST SP 800-63 Digital Identity Guidelines remains a useful reference for assurance and authenticator strength, while OWASP ASVS gives concrete expectations for authentication, session management, and access control.
Browser-session choices also need to be judged against real attack paths. If an attacker gets script execution, localStorage gives them an obvious theft path; if an attacker gets a session-bearing browser, cookie-based auth still requires CSRF-resistant design and careful cookie scoping. That is why the best answer is rarely "always localStorage" or "always cookies", it is "use the mechanism that best fits your threat model and enforce the surrounding controls correctly."
Risk and Threat Considerations
The main risk is that token storage can become the easiest way to turn a front-end bug into account compromise. When credentials are readable by JavaScript, XSS, supply-chain script injection, or malicious browser extensions can convert code execution into direct token theft. When credentials are hidden in HttpOnly cookies, the risk shifts toward session riding, CSRF, and misuse of an already-authenticated browser.
Failure mechanism: localStorage exposes bearer tokens to any script in the origin, so injected or compromised code can exfiltrate them and reuse them outside the browser. Cookie-based sessions fail differently if the app lacks CSRF protection, same-site discipline, or proper session scoping, because the browser will still attach the cookie to requests.
Impact: The result is account takeover, unauthorized API calls, and potentially broader privilege abuse if the stolen session or token carries high-value access. In SPA environments, the impact often spreads quickly because the same token is commonly reused across multiple backend calls and user actions.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST SP 800-63 and OWASP ASVS set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST SP 800-63 | Digital Identity Guidelines | Covers browser auth assurance and session strength for SPAs |
| Recommendation — Use assurance-aligned authenticators and short session lifetimes for SPA sign-in. | ||
| OWASP ASVS | V6 — Authentication | Directly addresses authentication design choices in web apps and SPAs |
| V7 — Session Management | Session handling determines whether cookies or tokens are safely usable | |
| V8 — Authorization | SPA tokens and cookies ultimately gate access decisions | |
| Recommendation — Verify authentication flows resist token theft and replay. Harden session storage, expiry, and invalidation for browser-based auth. Enforce least-privilege authorization for every API-backed session. | ||
Practitioner Guidance
What to prioritize: Treat the storage decision as a session architecture decision, not a front-end convenience choice. If you can support cookie-based auth safely, prefer HttpOnly cookies and pair them with CSRF protections, narrow cookie scope, and short session lifetimes.
What to verify: Confirm that your SPA does not rely on JavaScript access to the credential for ordinary UI behavior. If it does, check whether that dependency is really an architectural shortcut that can be removed, because any token exposed to script should be assumed stealable after XSS.
Common mistake: Assuming localStorage is acceptable because "the app already has XSS controls". XSS prevention matters, but storage choice should still reduce the damage if prevention fails.
Practitioner takeaway: If the architecture can support it, hide session material from JavaScript and make the browser enforce the session boundary; if it cannot, assume token theft is part of your XSS blast radius and design accordingly.
Related resources from NHI Mgmt Group
- Why is it crucial to adopt new authentication methods in MCP usage?
- When should organisations use self-signed TLS client authentication instead of CA-signed mTLS?
- Why do AI-driven phishing attacks still succeed when organisations use modern authentication?
- Should organisations use the same identity controls for internal agents and customer authentication?
Deepen Your Knowledge
Free weekly newsletter
Subscribe to the NHI & AI Identity Journal
The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.
Bonus 33% off our NHI Course when you subscribe.
Reviewed and updated by the NHIMG editorial team on October 11, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org