Cookies in Depth

Chapter 2
Cookies in Depth
Domain, Path, Expires/Max-Age, Secure, HttpOnly, and SameSite — the attributes that determine where a cookie goes and how safe it is

Chapter 1 introduced cookies as the one storage mechanism the server can read directly. What makes cookies genuinely complex — and the reason this chapter exists on its own — is the set of attributes that control exactly when a cookie gets sent, to which domains, and how exposed it is to scripts and attackers. Getting these wrong is one of the most common sources of real security bugs on the web.

Anatomy of a Set-Cookie Header

Every part after the first name=value pair is an attribute controlling the cookie's behaviour. Each is covered below.

Domain and Path — Where the Cookie Gets Sent

Domain
Without it, the cookie only applies to the exact host that set it. With Domain=osztromok.com, it's also sent to every subdomain (blog.osztromok.com, shop.osztromok.com) — a deliberate widening of scope.
Domain=osztromok.com → matches osztromok.com AND all subdomains
Path
Restricts the cookie to requests under a specific URL path. Path=/admin means the cookie is only sent for requests to /admin and anything beneath it — not the rest of the site.
Path=/admin → only sent for /admin, /admin/users, etc.
Setting Domain too broadly is a common mistake
Setting Domain when you only ever need the exact host widens the cookie's reach unnecessarily — if a subdomain is ever compromised or hosts user-generated content, that subdomain can also read (and forge) cookies meant only for your main site. Omit Domain entirely unless cross-subdomain sharing is a genuine requirement.

Expiry — Session Cookies vs Persistent Cookies

No Expires/Max-Age
A session cookie — deleted automatically when the browser closes. The right default for anything sensitive, like a login session.
Max-Age=3600
A persistent cookie — survives browser restarts, expiring after the given number of seconds (here, 1 hour) from when it was set.
Expires=<date>
Older syntax achieving the same goal as Max-Age, using an absolute date/time instead of a relative duration. Max-Age is generally preferred in modern code — simpler to reason about.

Secure and HttpOnly — The Two Security Attributes

Secure
The cookie is only ever sent over HTTPS, never plain HTTP — preventing it from being visible to anyone intercepting unencrypted traffic on the network. There is essentially no good reason to omit this on any site that has HTTPS available (which should be every site, per the security course's earlier coverage of Let's Encrypt).
HttpOnly
The cookie is invisible to JavaScript entirely — document.cookie simply won't include it. This is the single most effective defence against a cross-site scripting (XSS) attack stealing a session cookie, since even injected malicious JavaScript can't read it.
Always set both Secure and HttpOnly on session/auth cookies
A session identifier cookie with neither attribute is readable by any injected script (XSS) and visible to anyone on the same unencrypted network. There is virtually no legitimate reason for an authentication cookie to lack either flag — this is one of the few "always do this" rules in web security with essentially no exceptions.

SameSite — Controlling Cross-Site Requests

SameSite is the newest and most consequential attribute for this course specifically — it controls whether a cookie is sent when the request originates from a different site than the one that set it, which is exactly the mechanism behind cross-site tracking, and directly sets up Chapter 3's first-party/third-party distinction.

ValueBehaviourTypical use
Strict Never sent on cross-site requests, even when following a link from another site Highly sensitive actions (banking, account settings) where even a "click here to log in" link from email shouldn't auto-authenticate
Lax Sent on top-level navigation (clicking a link) but not on background cross-site requests (images, iframes, fetch from another site) The modern default in every major browser — balances usability and security for most cookies, including typical login sessions
None Sent on every request regardless of origin — requires the Secure attribute to also be set Genuinely needed cross-site use cases: a third-party embedded widget that needs its own login state, payment processor iframes
// A login session cookie — sensible modern defaults
Set-Cookie: session_id=a1b2c3d4; Secure; HttpOnly; SameSite=Lax; Path=/

// A cookie genuinely needed for cross-site embedding (rare)
Set-Cookie: widget_session=x9y8z7; Secure; SameSite=None; Path=/
SameSite=Lax is now the browser default if you don't specify anything
Modern browsers (Chrome since 2020, others following) treat cookies with no explicit SameSite attribute as Lax automatically — a deliberate, industry-wide shift toward safer defaults. This is part of the same broader trend covered in Chapter 4: browsers actively restricting cross-site cookie behaviour to limit tracking, which is the direct ancestor of the bounce-tracking warning this course exists to explain.

Reading and Inspecting Cookies in DevTools

Browser DevTools → Application (Chrome) or Storage (Firefox) tab → Cookies shows every cookie for the current site, including all the attributes covered in this chapter — genuinely the fastest way to debug "why isn't my cookie being sent" without guessing.

  • Check Secure first if a cookie isn't appearing on a request — testing on plain HTTP with a Secure cookie set will silently fail to send it.
  • Check the Domain column if a cookie set on one subdomain isn't visible on another — likely missing the Domain attribute, or set too narrowly.
  • Check SameSite if a cookie works on direct navigation but not when embedded in an iframe from another site — classic Lax-blocking-a-legitimate-cross-site-need scenario.

Chapter 2 Quick Reference

  • Domain — widens scope to subdomains; omit unless genuinely needed
  • Path — restricts to a URL path and beneath it
  • No Expires/Max-Age = session cookie (gone on browser close); Max-Age = persistent, relative duration
  • Secure — HTTPS only; HttpOnly — invisible to JavaScript, the main XSS defence for session cookies
  • Always set Secure + HttpOnly on auth/session cookies — essentially no valid exception
  • SameSite: Strict (never cross-site) / Lax (modern default, allows top-level nav) / None (always sent, requires Secure)
  • No explicit SameSite defaults to Lax in modern browsers automatically
  • Next chapter: first-party vs third-party cookies, and why browsers are cracking down on cross-site tracking