5 min read

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.