Learn / Security / Lesson 03

Sessions and cookies

What a session cookie must carry, the flags that protect it, and the trade-off between signed cookies and server-side sessions.

Last updated: 2026-09-19

What it is

HTTP forgets you between requests. A session is how the server remembers that this browser already signed in. The browser holds a cookie; the server trusts whatever that cookie proves. So whoever holds the cookie is the user, as far as the server can tell.

Why it is a rule

How to do it

The flags

http
Set-Cookie: session=<value>; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=28800
FlagWhat it stops
HttpOnlyJavaScript cannot read the cookie, so an injected script cannot steal it
SecureThe cookie is never sent over plain HTTP
SameSite=LaxOther sites cannot send it with a POST (see the CSRF lesson)
Max-AgeThe session ends on its own, even if nobody logs out

A cookie name starting with __Host- is refused by the browser unless it is Secure, has Path=/ and no Domain, so a subdomain cannot overwrite it.

What goes inside

The value must be impossible to guess or forge. Two common shapes:

js
const sign = (body, exp) =>
  crypto.createHmac('sha256', SECRET).update(`${body}.${exp}`).digest('base64url')

const valid = (cookie) => {
  const [body, exp, sig] = cookie.split('.')
  if (!sig || Date.now() > Number(exp)) return false
  const want = Buffer.from(sign(body, exp))
  const got = Buffer.from(sig)
  return want.length === got.length && crypto.timingSafeEqual(want, got)
}

timingSafeEqual matters: a normal === stops at the first wrong character, and the time it takes can leak how much of a guess was right.

The life of a session

How we do it here

Every session cookie is HttpOnly, SameSite=Lax, and Secure in production, is signed with HMAC-SHA256 and carries its own expiry. Signatures are compared in constant time. Access is checked on every request, not only at sign-in.

Benefits

Disadvantages

Checklist

Sources

Read this lesson as Markdown