Cookies (cookie-parser)
Cookies are small key/value pairs the server asks the browser to store and send back on every subsequent request — the backbone of sessions, auth tokens, and preferences. Express sets cookies with the built-in res.cookie(), but reading the incoming Cookie header is easier with the cookie-parser middleware, which populates req.cookies. The real subject of this page, though, is the security attributes that separate a safe cookie from a vulnerability.
Reading cookies with cookie-parser
import cookieParser from 'cookie-parser'
app.use(cookieParser()) // → req.cookies populated for every request
app.get('/dashboard', (req, res) => {
const theme = req.cookies.theme ?? 'light' // read an incoming cookie
res.send(`Theme: ${theme}`)
})Setting a cookie
res.cookie('theme', 'dark', {
httpOnly: true, // JS can't read it (XSS defense)
secure: true, // HTTPS only
sameSite: 'lax', // CSRF defense
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days, in milliseconds
path: '/',
})
// Remove a cookie:
res.clearCookie('theme')The security attributes that matter
Attribute | What it does | Protects against |
|---|---|---|
| Hides the cookie from | XSS token theft |
| Only sent over HTTPS | Network sniffing |
| Limits cross-site sending | CSRF |
| Scopes where the cookie is sent | Over-broad exposure |
| Lifetime | Stale long-lived sessions |
sameSite values
Value | Cookie sent on cross-site requests? |
|---|---|
| Never — even following a link from another site |
| Only on top-level navigations (GET) — a good default |
| Always — but then |
Signed cookies — tamper detection
// Provide a secret to enable signing:
app.use(cookieParser('a-long-random-secret'))
// Sign on the way out:
res.cookie('plan', 'pro', { signed: true, httpOnly: true })
// Verified on the way in — req.signedCookies, not req.cookies:
app.get('/account', (req, res) => {
const plan = req.signedCookies.plan // undefined if tampered/missing
res.json({ plan })
})Cookies vs server-side sessions
Two strategies for remembering a user between requests:
Cookie holds the data — small, stateless, but the client sees it and it ships on every request. Fine for non-sensitive prefs (theme, locale).
Cookie holds only a session id — the actual data lives server-side (memory/Redis/DB). Standard for auth; the cookie is an opaque key. This is what
express-sessionimplements.