JWT tokens can be stored in two main places, but each has security pros and cons.
The secure choice depends on whether you want to avoid XSS attacks or CSRF attacks.
✅ 1. HttpOnly Cookies (Most Secure Option)
Best practice for production apps
✔ Why?
- Browser stores token automatically
- JavaScript cannot access cookie → protects from XSS attacks
- Automatically sent with every request
✔ When to use?
- Login-based web apps (Google, Facebook, Amazon)
- Apps that need strong security
❌ Cons
- Cookies can be vulnerable to CSRF (but can be fixed using:
- SameSite=Lax/Strict
- CSRF token
- Double-submit cookies)
🔐 Example (Backend sets token in HttpOnly cookie)
res.cookie("token", jwtToken, {
httpOnly: true,
secure: true,
sameSite: "strict",
});
✅ 2. LocalStorage (Common but less secure)
Stores token as a string.
localStorage.setItem("token", jwtToken);
✔ Pros:
- Easy to use
- Accessible in JavaScript
- Good for SPA (React, Angular, Vue)
❌ Cons:
- Vulnerable to XSS attacks
- If someone injects JS → they can steal your token
When to use?
- Only if app is small
- Not highly sensitive
- You handle XSS properly
⚠️ 3. Session Storage
sessionStorage.setItem("token", jwtToken);
✔ Advantages:
- Clears when tab is closed
- Same XSS risk as localStorage
❌ Not ideal for long login sessions
🔥 Recommended Architecture (Industry Standard)
🔐 Access Token → HttpOnly Cookie
🔁 Refresh Token → HttpOnly Cookie
This is how modern secure apps work:
- Short-lived access token (5–15 mins)
- Long-lived refresh token (14–30 days)
🎯 Short Answer for Interview:
Store JWT in HttpOnly cookies for maximum security.
LocalStorage is easier but vulnerable to XSS.
SessionStorage is temporary and still XSS-prone.
The safest modern setup is Access Token + Refresh Token in HttpOnly cookies.