Secure cookies in Next.js — HttpOnly, Secure, SameSite explained
Misconfigured cookies are how session tokens leak. Here is exactly which flags to set for session, CSRF, and preference cookies in a Next.js app.
Session cookies are how your app keeps a user logged in. If they are not set with the right flags, they are reachable by injected JavaScript, readable over HTTP, or usable cross-origin.
What it is
HTTP cookies ship with a set of flags. `HttpOnly` stops JavaScript from reading them. `Secure` stops them from being sent over HTTP. `SameSite` controls cross-site request inclusion. The right combination depends on what the cookie is for.
Vulnerable example
// Vulnerable: all three flags missing.
cookies().set("session", token, {
path: "/",
// httpOnly: missing -> readable by any XSS
// secure: missing -> sent over HTTP if any link leaks
// sameSite: missing -> default 'lax', often fine but better explicit
});Fixed example
// Fixed: full hardening for a session cookie
cookies().set("session", token, {
path: "/",
httpOnly: true,
secure: true, // HTTPS only
sameSite: "lax", // blocks most CSRF; 'strict' for admin-only cookies
maxAge: 60 * 60 * 24 * 7,
});How Securie catches it
Securie audits every cookies().set() and every Set-Cookie emission, flagging any combination that puts a session-class cookie at risk.
Checklist
- Session cookies set HttpOnly + Secure + SameSite=lax
- CSRF-token cookies are NOT HttpOnly (JS needs to read them) but ARE Secure + SameSite=strict
- maxAge / Expires is set — not session cookies that persist until browser close
- Domain is not overly broad (avoid .example.com if only app.example.com needs the cookie)
- HTTPS is strict-enforced site-wide (HSTS header)
FAQ
SameSite strict or lax?
Lax for general session cookies. Strict for admin-area or payment-context cookies. None only when the cookie truly needs cross-site inclusion (third-party embeds) — and then Secure is mandatory.