principlejavascriptMajor
JWT Storage: httpOnly Cookies vs localStorage
Viewed 0 times
jwtlocalstoragehttponlycookiexsstoken storagesecure cookie
Problem
Storing JWTs in localStorage exposes them to any JavaScript running on the page, meaning an XSS vulnerability can silently exfiltrate all user tokens.
Solution
Store JWTs in httpOnly, Secure, SameSite=Strict cookies. The browser automatically sends them and JavaScript cannot read them.
Why
httpOnly cookies are inaccessible to JavaScript by design. Even if an attacker achieves script execution on the page, they cannot extract the token to replay it from another origin.
Gotchas
- httpOnly cookies are still vulnerable to CSRF—combine with CSRF tokens or SameSite=Strict
- SameSite=Strict breaks OAuth redirect flows that return tokens via cross-site navigation—use Lax for those
- Long-lived JWTs in cookies still need a refresh token rotation strategy
- Token revocation is harder with JWTs; maintain a server-side deny list for logout
Code Snippets
Setting JWT in httpOnly cookie on login
const jwt = require('jsonwebtoken');
app.post('/login', async (req, res) => {
const user = await authenticate(req.body);
if (!user) return res.sendStatus(401);
const token = jwt.sign({ sub: user.id, role: user.role }, process.env.JWT_SECRET, {
expiresIn: '15m'
});
res.cookie('access_token', token, {
httpOnly: true,
secure: true, // HTTPS only
sameSite: 'Strict', // CSRF protection
maxAge: 15 * 60 * 1000
});
res.json({ message: 'Logged in' });
});Revisions (0)
No revisions yet.