Why Storing JWT in localStorage Is a Security Nightmare and What to Use Instead
This article explains why storing JWT tokens in localStorage is unsafe due to XSS vulnerabilities, compares alternatives like HttpOnly cookies, BFF with cookies, and Service Workers, and offers guidance on choosing the most secure authentication strategy for modern frontend applications.
localStorage's "original sin": why it’s no longer safe
localStorageis vulnerable because XSS scripts can read it, allowing attackers to steal JWT tokens and impersonate users.
What is an XSS attack?
An XSS attack injects malicious JavaScript into a page, which can run in the context of the site and access any data stored in localStorage.
How XSS steals the token
When malicious script runs, it can read localStorage and send the JWT to an attacker‑controlled server, opening all backend APIs to the attacker.
Conclusion: localStorage is a sandbox fully exposed to JavaScript; storing sensitive JWTs there is like hanging your house key on a nail outside.
"Old‑school gentleman": HttpOnly Cookie – perfect solution?
Setting a cookie with the HttpOnly flag prevents JavaScript (e.g., document.cookie) from accessing it, so XSS cannot directly steal the token.
Advantages:
Effective XSS defense : JS cannot read the cookie.
Browser‑managed : No need to add Authorization header manually.
Drawback: It introduces CSRF risk.
What is a CSRF attack?
CSRF tricks a logged‑in user’s browser into sending an unintended request to a trusted site, automatically including the user’s cookies.
Solutions:
Set the cookie’s SameSite attribute to Strict or Lax to block cross‑site requests.
Use a CSRF token that the frontend must send with state‑changing requests.
While HttpOnly cookies work, they require careful backend configuration and CSRF protection, especially for cross‑origin scenarios.
2025 wave: New frontend authentication ideas
Idea 1: BFF (Backend for Frontend) + Cookie
The BFF sits between the UI and micro‑services, handling authentication and storing a session ID in a secure
HttpOnly SameSite=Strictcookie.
Authentication flow:
Login : Frontend sends credentials to the BFF.
Auth & token exchange : BFF obtains a JWT from the auth service.
Set secure cookie : BFF creates a session and returns a
HttpOnly SameSite=Strictcookie.
API request : Frontend calls the BFF; the browser automatically includes the cookie.
Proxy & token injection : BFF reads the session, adds the JWT to the request header, and forwards it to downstream services.
Pros: Top‑level security (JWT never reaches the browser), simple frontend code, clear separation of concerns.
Cons: Adds an extra BFF service, increasing architectural complexity.
Idea 2: Service Worker + In‑memory storage
The Service Worker holds the JWT in a variable inside its own execution context, never exposing it to the main thread.
Authentication flow:
Login : Main thread sends the JWT to the active Service Worker via postMessage.
In‑memory storage : Service Worker keeps the token in a scoped variable (no localStorage or IndexedDB).
Request interception : The Service Worker intercepts outgoing fetch calls, clones the request, and injects the Authorization header with the stored token.
Send request : The modified request is sent to the network.
Pros: Strong isolation—XSS cannot reach the token; token refresh logic can be encapsulated; no extra backend service needed.
Cons: More complex to implement, lifecycle management, and browser compatibility concerns.
The era of storing JWTs in localStorage is ending. For new projects or major refactors, adopt the BFF + Cookie pattern for top‑grade security. Teams focused on cutting‑edge frontends or PWAs may explore the Service Worker approach. Small apps that cannot add a BFF should still prefer HttpOnly cookies with strict SameSite and CSRF tokens over localStorage.
JavaScript
Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
