When architecting a Single Page Application (SPA) in frameworks like React, Angular, or Vue, developers inevitably reach a crossroads: Where should I store my access tokens once they are returned to the browser? This architectural decision is one of the most widely debated topics in our developer community.
Storing Tokens in Web Storage (localStorage / sessionStorage)
The Pros: Simple to implement; access tokens are immediately accessible via vanilla JavaScript to construct Authorization: Bearer fetch headers.
The Cons: Extremely Vulnerable to Cross-Site Scripting (XSS). If a single malicious dependency, tracking pixel, or injected script executes on your page, it can access Web Storage, extract your token, and exfiltrate it to an external server.
Storing Tokens in HTTP-Only Cookies
The Pros: Setting the HttpOnly flag on cookie makes it entirely inaccessible to browser-side Javascript, effectively neutralizing standard XSS-based token theft.
The Cons: Introduces vulnerability to Cross-Site Request Forgery (CSRF). If a user visits a malicious site while logged into your app, the browser will automatically append the cookie to a request made to your API. Additionally, managing cookies across cross-domain APIs can be a routing and CORS headache.
The Forum Debate: Developers constantly argue whether cookies really solve all security woes. Read the community thread to understand the nuance of cookie-based risks.
The Best-Practice Resolution: The BFF Pattern and In-Memory JWTs
To balance both security models, modern identity specifications recommend utilizing the Backend-for-Frontend (BFF) pattern or In-Memory JWTs with Secure Session Cookies:
In-Memory Storage: The SPA stores the active access token strictly in a secure, non-global JavaScript variable (e.g., React Context or state). It cannot be read from the DOM and is secure from simple XSS attacks. See the official documentation on tokens vs. cookies best practices.
Session Persistence: Because browser state is cleared on page refresh, the SPA establishes a secure session cookie with the authorization server. This session cookie is a set to HttpOnly, Secure, and SameSite=Strict.
Silent Authentication: When the page is reloaded or the in-memory access token expires, the client uses a hidden iframe or background call to fetch a fresh token silently from the authorization server. Because the browser automatically passes the secure session cookie, the identity provider issues a new token without requiring the user to type their password again.