HTTP-Only Cookies
Overview
Once a backend generates a JWT, you have to send it to the frontend. The frontend usually saves it in localStorage. This is a catastrophic security vulnerability. If a hacker runs a Cross-Site Scripting (XSS) attack on your site, they can use window.localStorage.getItem('token') to steal the JWT. HTTP-Only Cookies solve this. It is a special header sent by the backend. The browser saves the cookie, but physically blocks frontend JavaScript from ever reading it, making it 100% immune to XSS token theft.
Syntax
// npm install cookie-parser
const cookieParser = require('cookie-parser');
app.use(cookieParser()); // Middleware to parse incoming cookies
app.post('/api/login', (req, res) => {
const token = jwt.sign({ id: 42 }, process.env.JWT_SECRET);
// --- THE GOLD STANDARD OF TOKEN DELIVERY ---
res.cookie('auth_token', token, {
httpOnly: true, // CRITICAL: Blocks JavaScript from reading the cookie!
secure: true, // CRITICAL: Cookie is only sent over HTTPS!
sameSite: 'strict', // CRITICAL: Protects against CSRF attacks!
maxAge: 3600000 // Expires in 1 hour (in milliseconds)
});
res.json({ success: true, message: "Logged in securely!" });
});
app.get('/api/protected', (req, res) => {
// The browser AUTOMATICALLY attaches the cookie to every subsequent request!
// The frontend developer doesn't have to write any headers in their fetch() call.
const token = req.cookies.auth_token;
});Common Pitfalls
- Forgetting
credentials: 'include'on the frontend. If your React app usesfetchoraxiosto talk to an API on a different domain, the browser will refuse to send the HTTP-Only cookie automatically unless the frontend explicitly enables the credentials flag in the network request. - Cross-Site Request Forgery (CSRF). While HTTP-Only cookies solve XSS (Token Theft), they are vulnerable to CSRF. If a logged-in user visits a hacker's website, the hacker can trick the user's browser into making an API request to your bank. Because cookies attach automatically, the bank thinks it's a valid request. Always use the
sameSite: 'strict'flag to prevent cookies from leaving the domain.
Interview Questions
The frontend can't read the token, but it doesn't need to. The industry standard is to provide a separate /api/me endpoint. On page load, React hits /api/me (the cookie is automatically sent). If the backend returns 200 with the user's profile data, React knows they are logged in. If it returns 401, React redirects to the login screen.
Real-World Example
How to properly log a user out when using HTTP-Only cookies. You cannot delete the cookie from the frontend; the backend must explicitly clear it.
app.post('/api/logout', (req, res) => {
// Re-sends the cookie with a Max-Age of 0,
// forcing the browser to instantly delete it from disk!
res.clearCookie('auth_token', {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
res.json({ success: true, message: "Logged out" });
});Check Your Knowledge
Test your understanding of HTTP-Only Cookies with these quick questions.