Cookies in Depth
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=osztromok.com, it's also sent to every subdomain (blog.osztromok.com, shop.osztromok.com) — a deliberate widening of scope.
Path=/admin means the cookie is only sent for requests to /admin and anything beneath it — not the rest of the site.
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
Secure and HttpOnly — The Two Security Attributes
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.
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.
| Value | Behaviour | Typical 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 |
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=/
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