Storing a JWT in localStorage is risky because any client-side JavaScript can access it, making it vulnerable to cross-site scripting (XSS) attacks, while also lacking protection against cross-site request forgery (CSRF) and providing no built-in safeguards against token theft.
Storing JWT in localStorage is considered a security anti-pattern because localStorage is accessible to any JavaScript code running on the same origin. If an attacker can inject a malicious script via an XSS vulnerability — even from a compromised third‑party library — that script can trivially read the token from localStorage and exfiltrate it to an attacker-controlled server . Unlike httpOnly cookies, localStorage offers no mechanism to prevent JavaScript from accessing the token, meaning a single XSS hole can lead to complete account takeover .
Beyond XSS, localStorage also lacks protection against cross-site request forgery (CSRF). While CSRF is typically a concern for cookie-based authentication, the primary risk with localStorage is XSS; however, if an application uses localStorage to store a JWT and relies solely on JavaScript to attach it as an Authorization header, CSRF is not automatically mitigated either. Moreover, tokens stored in localStorage persist indefinitely across browser sessions, increasing the window of exposure if a token is stolen . Long-lived tokens (e.g., 7 days) provide attackers with persistent, undetected access to user accounts .
XSS Vulnerability: localStorage is accessible to any JavaScript on the page, including malicious scripts injected via XSS .
Persistent Exposure: Tokens remain in localStorage after the browser is closed; if stolen, they provide long-term access .
No httpOnly Protection: Unlike cookies, localStorage cannot be marked httpOnly, so client‑side scripts have unrestricted access .
Token Persistence: Long-lived tokens (e.g., 7 days) give attackers extended session hijacking capabilities without user awareness .
Compromised Dependencies: Even if your code is XSS‑free, a compromised npm dependency can read and exfiltrate the token .
CSRF Considerations: While not the primary risk, localStorage does not inherently protect against CSRF; proper CSRF tokens or sameSite cookies are still needed .
The industry standard for production applications is to store JWTs in httpOnly, Secure, SameSite=Strict cookies. These cookies are not accessible via JavaScript, eliminating the XSS token theft vector entirely . The browser automatically sends the cookie with requests, reducing the need for manual token handling. To protect against CSRF, combine httpOnly cookies with sameSite=Strict or use anti‑CSRF tokens for state‑changing requests . For short-lived access tokens, consider storing them in memory (e.g., in a closure or React state) and using a refresh token stored in an httpOnly cookie to obtain new access tokens silently .