FrontendPrep
Back to Web Security Questions
securityMedium

Web Security: Token Storage (Cookies vs LocalStorage)

Learn where to securely store JWTs and authentication tokens in web applications, comparing LocalStorage, SessionStorage, and secure Cookies.

Web Security: Token Storage (Cookies vs LocalStorage)

When implementing authentication in frontend applications (like JWT-based auth), you must decide where to store the user's access and refresh tokens.

The choice of storage determines how vulnerable your application is to two major web security attacks: Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF).


1. LocalStorage and SessionStorage

LocalStorage and SessionStorage are key-value databases built into the browser.

  • LocalStorage: Persists data even after the browser window is closed.
  • SessionStorage: Clears data automatically when the browser tab is closed.

The Security Vulnerability: XSS

Any JavaScript code running on the same domain has full read/write access to LocalStorage and SessionStorage via window.localStorage.

// Extremely easy for malicious scripts to read
const token = localStorage.getItem("auth_token");
sendToAttackerServer(token);

If your website contains a Cross-Site Scripting (XSS) vulnerability (e.g., an unescaped comment box loading a malicious <script>), an attacker can easily write a script to steal all your users' tokens.


2. Cookies

Cookies are small text files stored by the browser. When the frontend makes an API request to the backend, the browser automatically attaches the relevant cookies in the Cookie header.

The Security Vulnerability: CSRF

Because browsers attach cookies automatically to requests, cookies are vulnerable to Cross-Site Request Forgery (CSRF).

If a user visits a malicious site evil.com while logged into mybank.com, the malicious site can submit a hidden form requesting mybank.com/transfer. The browser will attach the authentication cookies automatically, executing the unauthorized request.

The Mitigations (How to make Cookies Secure):

To protect cookies from XSS and CSRF, you must configure them with three essential attributes:

  1. HttpOnly: Blocks JavaScript code from reading or writing the cookie (via document.cookie). This completely immunizes the token against XSS-based theft.
  2. Secure: Enforces that the cookie is only transmitted over encrypted HTTPS connections, preventing network interception.
  3. SameSite: Restricts the browser from sending cookies on cross-origin requests, blocking CSRF attacks:
    • SameSite=Strict: Cookie is only sent if the site matches the URL bar exactly.
    • SameSite=Lax: Cookie is sent on same-site requests and safe top-level navigations (clicking a link), but blocked on cross-origin forms. This is the recommended default.
# Example secure HTTP response header setting a cookie
Set-Cookie: token=xyz123; Secure; HttpOnly; SameSite=Lax; Path=/

3. Best Practice Architecture

What is the industry standard for storing auth tokens?

Store the JWT token inside a Secure; HttpOnly; SameSite=Lax cookie.

  • Because it is HttpOnly, XSS attacks cannot steal it.
  • Because it is SameSite=Lax, CSRF attacks cannot abuse it.

If your APIs require you to attach the token manually in the Authorization: Bearer <token> header:

  1. Access Token: Store it in React state/memory. It is secure from XSS because it is temporary, but is cleared on page refresh.
  2. Refresh Token: Store it in an HttpOnly; Secure; SameSite=Lax cookie.
  3. Silent Refresh: When the page refreshes or the access token expires, the client makes an API call. The browser automatically sends the secure refresh cookie, and the server returns a new access token to the memory store.

Key Takeaways

  • LocalStorage is highly vulnerable to XSS (Cross-Site Scripting) attacks. Any JavaScript script running on the page can steal the stored tokens.
  • Cookies are vulnerable to CSRF (Cross-Site Request Forgery) attacks because the browser automatically attaches them to cross-site requests.
  • Enforce cookie safety by applying HttpOnly (blocks JavaScript extraction), Secure (requires HTTPS), and SameSite=Lax (blocks CSRF cross-origin submissions).
  • The safest pattern is to store sensitive authentication credentials inside HttpOnly; Secure; SameSite=Lax cookies rather than LocalStorage.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.