Working with Cookies for Authentication
1. Setting Authentication Cookies
| Header | Example |
| Set-Cookie | __Host-sid=abc...; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=28800 |
| Read | Client → automatic on same-origin requests |
| Clear | Set-Cookie: sid=; Max-Age=0; Path=/ |
2. Using Cookie Attributes
| Attribute | Effect | Recommended |
| HttpOnly | JS cannot read via document.cookie | Always for auth |
| Secure | Sent over HTTPS only | Always |
| SameSite | Lax / Strict / None | Lax (default) |
| Domain | Limits which hosts receive cookie | Omit unless needed |
| Path | Limits URL path scope | / |
| Max-Age / Expires | Persistence | Match session policy |
| Partitioned NEW | CHIPS — partitioned by top-level site | Third-party contexts |
3. Understanding SameSite Attribute
| Value | Behavior | Use Case |
| Strict | Never sent cross-site (including top-level nav) | Banking, no inbound links |
| Lax | Sent on top-level GET nav only | Standard apps (default in modern browsers) |
| None | Sent cross-site (requires Secure) | Third-party widgets, SSO iframes |
4. Setting Cookie Domain and Path
| Scenario | Setting |
| Single host | Omit Domain (host-only) |
| Share across subdomains | Domain=example.com |
| Limit to API | Path=/api |
| Strictest | __Host- prefix: no Domain, Path=/, Secure |
5. Implementing Cookie Expiration
| Type | Lifespan |
| Session cookie | Until browser closes (no Max-Age) |
| Persistent | Max-Age in seconds (or Expires UTC) |
| Server-revocable | Set Max-Age=0 on revoke endpoint |
6. Using Signed Cookies
Example: HMAC-signed cookie
import { createHmac, timingSafeEqual } from "crypto";
const sign = (v) => v + "." + createHmac("sha256", SECRET).update(v).digest("base64url");
const verify = (cookie) => {
const [v, sig] = cookie.split(".");
const expected = createHmac("sha256", SECRET).update(v).digest();
const actual = Buffer.from(sig, "base64url");
return actual.length === expected.length && timingSafeEqual(actual, expected) ? v : null;
};
7. Encrypting Cookie Values
| Need | Approach |
| Confidentiality | AES-256-GCM (AEAD) |
| Key rotation | Key ID prefix, support multiple keys |
| Library | iron-session, cookie-encrypter, NextAuth |
| Anti-pattern | ECB mode, custom XOR |
8. Implementing Cookie Prefixes
| Prefix | Enforced Constraints |
| __Secure- | Must include Secure attribute |
| __Host- | Secure + Path=/ + no Domain attribute |
Note: __Host- prefix prevents subdomain attackers from setting cookies that override yours.
9. Handling Cookie Consent
| Cookie Category | Consent Required? |
| Strictly necessary (auth, CSRF) | No (legitimate interest) |
| Functional (UI prefs) | Usually yes (GDPR) |
| Analytics | Yes |
| Marketing / tracking | Yes, opt-in |
10. Preventing Cookie Theft
| Vector | Mitigation |
| XSS | HttpOnly, CSP, sanitization |
| Network | Secure + HSTS + TLS 1.3 |
| Subdomain takeover | __Host- prefix |
| Physical access | Short expiry + re-auth |
| Malicious extensions | Token binding (DBSC) |
11. Mitigating CSRF with Cookies
| Technique | Detail |
| SameSite=Lax/Strict | Primary defense (browser-enforced) |
| CSRF token | Synchronizer pattern: hidden form field matches cookie/session |
| Double-submit cookie | JS reads CSRF cookie, sends as header; server compares |
| Custom header | Require X-Requested-With on JSON APIs (triggers preflight) |
| Origin/Referer check | Server validates origin matches expected |