Introduction
JSON Web Tokens (JWT) are widely used for authentication in modern web applications. They help verify user identity without storing session data on the server. But a common question among developers is: “Where should I store my JWT token — in localStorage or in cookies?”
This guide will explain both approaches in simple words, discuss their security implications, and help you choose the best method for your Next.js, React, Angular, or Node.js app. You’ll also see examples and best practices for keeping JWTs safe from attacks.
What is a JWT Token?
A JWT (JSON Web Token) is a compact, secure way to represent user data between a client and server. After a user logs in, the server generates a token that contains encoded information like:
{
"userId": "12345",
"email": "[email protected]",
"role": "admin"
}
This token is signed using a secret key, ensuring its authenticity. The client stores this token and includes it with every request to prove the user’s identity.
Example of a JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsImVtYWlsIjoiZXhhbXBsZUBkb21haW4uY29tIn0.uKkhH8QNUZKJfRHF1a_jkXfVZhEN9eCMo64hO_xXYYA
Now, let’s explore where and how to store it securely.
Option 1. Storing JWT in localStorage
What is localStorage?
localStorage is a built-in browser storage system that stores key-value pairs on the client side. Data saved here persists even after refreshing or closing the browser.
Example
// Store token
localStorage.setItem('token', jwtToken);
// Retrieve token
const token = localStorage.getItem('token');
✅ Advantages of Using localStorage
Easy to Use – Simple JavaScript API for storing and retrieving tokens.
Persistent Storage – Tokens stay in the browser even after the page reloads or browser restarts.
Framework Independent – Works with any front-end framework like React, Angular, or Vue.
⚠️ Disadvantages of localStorage
Vulnerable to XSS (Cross-Site Scripting) – If an attacker injects JavaScript into your website, they can easily read the JWT from localStorage.
No Built-In Expiry – You must manually handle token expiration.
Not Automatically Sent to Server – You need to manually attach the token in the request headers:
axios.get('/api/profile', {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
});
🛡️ Security Tips for localStorage
Use strong Content Security Policy (CSP) to prevent XSS.
Avoid storing sensitive data (like passwords or secrets) in the token.
Always sanitize user input to block malicious scripts.
Consider rotating JWTs regularly and using short expiration times.
Option 2. Storing JWT in Cookies
What Are Cookies?
Cookies are small pieces of data that a server sends to a user's browser. They are automatically included with every HTTP request made to the server.
Example of setting a cookie:
res.cookie('token', jwtToken, {
httpOnly: true,
secure: true,
sameSite: 'Strict',
maxAge: 3600000 // 1 hour
});
✅ Advantages of Using Cookies
More Secure (when HttpOnly) – Cookies can be marked
HttpOnly, preventing JavaScript access and reducing XSS risk.Automatic Transmission – The browser automatically sends cookies with every request to the same domain.
Built-In Expiry – You can control how long a cookie stays valid.
⚠️ Disadvantages of Cookies
Vulnerable to CSRF (Cross-Site Request Forgery) – Since cookies are automatically sent with requests, an attacker can trick users into making unintended requests.
Limited Storage – Cookies can only store up to 4KB of data.
CORS Configuration Required – When using cookies across different domains, you need to configure CORS properly.
Example of enabling credentials in Express
app.use(cors({
origin: 'https://yourdomain.com',
credentials: true
}));
And in frontend (React/Next.js)

Join the conversation! Your thoughts help the community grow.