Cookie Auth Details

HttpOnly, Secure, SameSite — the Three That Matter

Cookie Auth Details

Every cookie-based auth scheme depends on these three flags. Get them right.

3 min read Level 2/5 #express#cookies#security
What you'll learn
  • Set HttpOnly correctly
  • Use Secure in production
  • Pick a SameSite value

The previous lesson set cookie flags. This lesson explains why each one matters, and what breaks when you get it wrong.

HttpOnly: true

JavaScript on the page cannot read an HttpOnly cookie:

document.cookie     // doesn't include HttpOnly cookies

Why it matters: if your site has an XSS bug, the attacker’s JS cannot exfiltrate the session cookie. Without HttpOnly, one small XSS = total account takeover.

Always on for session/auth cookies.

Secure: true

The cookie is only sent over HTTPS. Over plain HTTP, the browser doesn’t include it.

In production: always on. Without it, a network attacker can sniff session cookies on the wire.

In local dev (HTTP): set it to false, or the cookie won’t stick to your http://localhost server.

SameSite

When does the browser send your cookie to your domain from elsewhere?

ValueWhen sent
StrictOnly on top-level requests from your domain
LaxSame-site requests + top-level GETs cross-site (e.g. clicking a link to you)
NoneAlways — but requires Secure: true

Lax is the modern default. It prevents most CSRF (no cross-site POSTs send your cookie) while still letting users follow links to you and stay logged in.

Strict is more secure but breaks “click an email link → you’re logged in” flows. Use it for very sensitive cookies, fine to use Lax for everything else.

None is needed for cross-origin SPAs that hit your API. Always pair with Secure.

CSRF Protection

With SameSite=Lax, most CSRF attacks already fail. For complete protection, add CSRF tokens for state-changing requests (covered in the CSRF lesson).

cookie: {
  maxAge: 24 * 60 * 60 * 1000,   // 24 hours in ms
}

Session cookies (no maxAge) die when the browser closes. Persistent cookies survive — handy for “remember me.”

Tip: rotate the session ID periodically. express-session has req.session.regenerate(cb) — call it after sensitive operations (login, privilege change).

Clearing

res.clearCookie(name) removes a cookie. To clear a cookie set with options, pass matching options:

res.clearCookie("session", { path: "/", domain: ".example.com" });

If the options don’t match, browsers may not clear it.

For new projects, this triple is the right default:

{
  httpOnly: true,
  secure:   process.env.NODE_ENV === "production",
  sameSite: "lax",
}

Memorize it. Apply it everywhere you set cookies.

JWT →