Why Storing JWT in localStorage Is No Longer Safe and What to Use Instead
Storing JWT tokens in localStorage has become a serious security risk because XSS attacks can steal them, so developers should adopt safer alternatives such as HttpOnly cookies, BFF‑backed sessions, or Service Worker‑based in‑memory storage, each with its own trade‑offs.
Why storing JWTs in localStorage is insecure
Cross‑Site Scripting (XSS) allows an attacker‑controlled script to run with the same privileges as the page’s own JavaScript. Because localStorage is accessible to any script running in the origin, a successful XSS injection can read the stored token and exfiltrate it to a remote server, giving the attacker full impersonation rights on protected APIs.
HttpOnly cookies as a classic mitigation
Setting the HttpOnly flag on a cookie prevents client‑side JavaScript (e.g., document.cookie) from reading the cookie. The browser automatically includes the cookie in every request to the cookie’s scope.
Advantages : blocks XSS‑based token theft; no manual token handling in frontend code.
Drawbacks : introduces Cross‑Site Request Forgery (CSRF) risk and requires server‑side configuration such as SameSite and CSRF tokens.
CSRF mitigation techniques
SameSite attribute : set SameSite=Strict or SameSite=Lax on the cookie to stop browsers from sending it on cross‑origin requests.
CSRF token : server generates a random token per session; the frontend must include this token in state‑changing requests (header or body) and the server validates it.
2025‑oriented frontend authentication patterns
Approach 1 — Backend‑for‑Frontend (BFF) + HttpOnly cookie
The BFF acts as a dedicated backend for the SPA. It handles authentication, stores the JWT internally, and exposes a session identifier via a secure cookie.
Login : the SPA posts credentials to the BFF.
Token exchange : the BFF forwards the credentials to the auth service, receives a JWT, and keeps it in server memory.
Set secure cookie : the BFF creates a session ID and returns it in an
HttpOnly SameSite=Strictcookie. The JWT never reaches the browser.
API request : the SPA calls the BFF (e.g., /api/user) with withCredentials. The browser automatically sends the session cookie.
Proxy & auth : the BFF validates the session, injects the stored JWT into the Authorization header, and forwards the request to downstream micro‑services.
Pros : highest security (JWT never exposed), clear separation of concerns, minimal frontend changes.
Cons : adds an extra service layer and operational complexity.
Approach 2 — Service Worker + in‑memory token
A Service Worker runs in a separate thread and can hold the token in a scoped variable, isolated from the page’s JavaScript.
Login : after successful authentication, the main thread sends the JWT to the active Service Worker via postMessage.
In‑memory storage : the Service Worker stores the token in a module‑level variable (no localStorage or IndexedDB).
Request interception : the Service Worker listens to fetch events, clones each outgoing request, and adds an Authorization: Bearer <token> header.
Send request : the modified request is forwarded to the network.
Pros : strong isolation—XSS scripts cannot access the token; token refresh logic can be encapsulated inside the worker.
Cons : more complex lifecycle management, browser compatibility considerations, and higher frontend implementation overhead.
Recommendation summary
For new projects or major refactors, adopt BFF + HttpOnly cookie to achieve top‑tier security despite the added architectural cost.
For PWA‑focused teams that prefer a pure‑frontend solution and can tolerate higher complexity, consider the Service Worker pattern.
If introducing a BFF is not feasible, use HttpOnly cookies with strict SameSite policies and CSRF tokens—still far safer than storing JWTs in 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.
