Script Valley
Authentication From Scratch
JWT AuthenticationLesson 3.3

Where to store JWTs in the browser

localStorage vs httpOnly cookie, XSS risk, CSRF risk, token storage tradeoffs, Authorization header, Bearer token pattern

The Storage Dilemma

Where you store a JWT in the browser has major security implications. There is no perfect option โ€” only tradeoffs.

localStorage

Pros: easy to access, no CSRF risk, works with the Authorization header pattern. Cons: any JavaScript running on the page can read it. If your site has an XSS vulnerability, an attacker can steal all JWTs stored in localStorage. This is a significant risk for apps that load third-party scripts.

HttpOnly Cookie

Pros: JavaScript cannot read it at all, so XSS attacks cannot steal the token directly. Cons: the browser automatically sends cookies with requests, which means CSRF attacks become possible again. Mitigate with SameSite=Strict or a CSRF token.

The Practical Recommendation

For most apps: store the JWT in an httpOnly cookie. This is the more defense-in-depth approach. XSS is extremely common; CSRF is more controllable with SameSite. When using the Authorization header (common in mobile apps and pure APIs), localStorage is acceptable if you have a strict Content Security Policy to reduce XSS exposure.

// Sending token in Authorization header
fetch('/api/profile', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Up next

Access tokens and refresh tokens explained

Sign in to track progress

Where to store JWTs in the browser โ€” JWT Authentication โ€” Authentication From Scratch โ€” Script Valley โ€” Script Valley