Skip to main content
Foundations progress
beginnerPage 6 of 50

HTTP Headers & Cookies

How HTTP requests and responses carry metadata, and the cookie mechanism that lets stateless HTTP remember who you are.

HTTP Headers & Cookies

In one line: Headers are the envelope on the HTTP letter. Cookies are a note the server wrote, sealed inside the envelope, and re-sent on every visit.

New here? Read top to bottom — every concept on this page builds on the previous one. The two ideas to take away: (1) headers are metadata, (2) cookies are how the web remembers you.

Comfortable with HTTP basics? Skim the headers tables, then focus on the cookie attributes table and the "safe cookie recipe."

Reference mode. This page collapses to: (1) common headers, (2) the four cookie security attributes, (3) sessions vs JWTs. Jump straight to whichever you need.

In plain English

The body of an HTTP message is the content — the JSON, the HTML, the image data. The headers are everything else: who you are, what format you want, what language you speak, whether you'll accept compressed data, what site sent you. A cookie is just one specific header (Cookie) that holds tokens the server wrote and is sending back. That's it.

What headers are

Headers are key-value pairs of metadata attached to every HTTP request and response. There are hundreds of standard headers. You'll use a few dozen regularly.

Key-value metadata on requests/responses. The ones below are the high-frequency set.

The most important request headers

  • Host — Which site at this IP you want (a single IP can serve many domains).
  • User-Agent — What browser/client you are.
  • Accept — What content types you can handle (application/json, text/html).
  • Accept-Language — Preferred languages (e.g., en-US,en;q=0.9).
  • Authorization — Auth credentials (typically Bearer <token>).
  • Cookie — Stored cookies for this domain.
  • Content-Type — Type of the request body.
  • Content-Length — Size of the request body.
  • Origin / Referer — Where the request came from (used for CORS and analytics).

The most important response headers

  • Content-Type — Type of the response body.
  • Content-Length — Size of the response body.
  • Set-Cookie — "Hey browser, store these cookies."
  • Cache-Control — How to cache this response.
  • ETag — A version identifier for caching.
  • Location — Where to redirect to (used with 3xx codes).
  • Access-Control-Allow-Origin — CORS permissions.
  • Content-Security-Policy — Security restrictions for the page.
🤔 Quick check
Worked example: read a real response
HTTP/2 200 OK
content-type: application/json; charset=utf-8
content-length: 1289
cache-control: public, max-age=300, stale-while-revalidate=60
etag: W/"509-h6k8t"
set-cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
access-control-allow-origin: https://example.com
content-security-policy: default-src 'self'

In English: "I'm returning 200 OK with a JSON response of 1289 bytes. Cache me for 5 minutes, and you can serve stale-while-revalidating for another minute. The content version is 509-h6k8t — re-ask me later with this tag to check. Also, please store this session cookie (which JavaScript cannot read, only sent over HTTPS, and only on same-site requests). CORS (Cross-Origin Resource Sharing — the browser rule that lets one site read responses from another) is allowed only from example.com. By the way, CSP (Content Security Policy — a browser-enforced allowlist of what scripts/images/etc. a page may load) restricts resource loads to the page's own origin."

Cookies — adding state to a stateless protocol

HTTP is stateless, which means each request is independent — the server has no memory of past requests by default. But your bank obviously needs to remember you between requests, otherwise you'd be re-logging in every time you click a link. That's what cookies do.

A cookie is a small piece of data the server tells the browser to store and re-send on every subsequent request to the same domain.

HTTP is stateless (each request is independent — the server has no memory of past requests by default). But your bank needs to remember you between requests. That's what cookies do.

A cookie is a small piece of data the server tells the browser to store and re-send on every subsequent request to the same domain. The full flow:

Cookies are how stateless HTTP gets a session. Server sends Set-Cookie; browser auto-attaches Cookie on subsequent same-domain requests.

Reading this diagram: The Set-Cookie response header is the one-time hand-off — it happens once, right after login. After that, the Cookie request header rides on every future request automatically, without you doing anything. That's how the server keeps recognizing you without you logging in again. The cookie made an otherwise stateless conversation feel like an ongoing session.

Reading this diagram: The Set-Cookie response header is the one-time hand-off. After that, the Cookie request header rides on every future request automatically — that's how the server keeps recognizing you without you logging in again.

🤔 Quick check

When the server sends Set-Cookie, it can attach modifiers that control how the cookie behaves:

AttributeWhat it doesWhy you care
HttpOnlyJavaScript on the page can't read itPrevents XSS attacks from stealing tokens
SecureOnly sent over HTTPSPrevents leakage on insecure networks
SameSite=StrictCookie never sent on cross-site requestsStrongest CSRF protection
SameSite=LaxSent on top-level navigations, not on embedded requestsReasonable default
SameSite=NoneSent on all cross-site requests (requires Secure)Needed for third-party embeds
Max-Age=NCookie lives for N secondsShort tokens are safer
Expires=DATECookie lives until a specific dateOlder style; Max-Age is preferred
Domain / PathRestricts which URLs the cookie is sent toUseful for multi-subdomain apps
Highlight: the four-attribute "safe cookie" recipe

For an authentication cookie in 2026, you almost always want:

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
  • HttpOnly → JavaScript can't read it (XSS-safe).
  • Secure → Only sent over HTTPS.
  • SameSite=Lax → Reasonable CSRF protection without breaking common flows.
  • Max-Age → Expires automatically; don't keep an auth token alive forever.

Set those four things and you've already avoided ~95% of the common cookie security mistakes.

🤔 Quick check

Sessions vs JWTs (the two flavors of tokens)

After you log in, the server needs some way to recognize you on every following request. There are two common ways to do this — both arrive in the browser as cookies, but they work very differently under the hood.

Session tokens (server-stored):

  1. The server makes up a random string and writes it down in its database (or Redis) along with your user ID.
  2. It sends that string to your browser as a cookie.
  3. On each request, the server takes the string out of your cookie, looks it up, and finds your user account.

Think of it like a coat-check ticket. The ticket itself is meaningless — the server has the coat with your name on it.

Pros: Easy to log someone out (just delete the row); the cookie is tiny. Cons: Every request requires a database lookup.

JWTs (JSON Web Tokens) (self-contained):

  1. The server builds a small JSON object (your user ID, expiration, etc.) and signs it cryptographically with a secret only it knows.
  2. It sends the whole signed JSON to your browser.
  3. On each request, the server just checks the signature. If the signature is valid, it trusts the user ID inside — no database lookup.

Think of it like a stamped event ticket. Anyone with the stamp can verify it's real, no central list needed.

Pros: No shared session storage, scales horizontally for free. Cons: Hard to invalidate before the expiration date; bigger cookie.

In 2026, session tokens are making a comeback because their downsides matter less with modern Redis/edge KV, and they're simpler to reason about. JWTs are still appropriate for microservices and APIs where stateless auth is valuable.

After authentication, the server needs to recognize the user on future requests. There are two dominant approaches — both delivered via cookies, but with very different mechanics:

Session tokens (server-stored):

  1. Server generates a random string, stores it in DB/Redis along with the user ID.
  2. Sends it to the client as a cookie.
  3. On each request, server looks up the token to find the user.

Pros: Easy to revoke (delete the row); small cookie size. Cons: Requires storage and a lookup per request.

JWTs (JSON Web Tokens) (self-contained):

  1. Server creates a JSON payload (user ID, expiration, etc.) and signs it with a secret.
  2. Sends it to the client.
  3. On each request, server verifies the signature — no DB lookup needed.

Pros: Stateless, scales horizontally without shared session storage. Cons: Hard to revoke before expiration; larger cookie size.

In 2026, session tokens are making a comeback because their downsides matter less with modern Redis/edge KV, and they're simpler to reason about. JWTs are still appropriate for microservices and APIs where stateless auth is valuable.

Session tokenJWT
StorageServer (DB/Redis)Client only
Per-request cost1 lookupSignature verify
RevocationDelete rowHard (needs deny-list)
SizeSmall (~32 bytes)Larger (300+ bytes)
Best forMost webapps in 2026Microservices, stateless APIs

2026 default: session tokens. JWTs where statelessness is load-bearing.

Try it yourself

Open any logged-in website you use. In DevTools, go to Application → Storage → Cookies. You'll see every cookie that site has set on your browser. Pick one labeled session or auth — note the HttpOnly, Secure, and SameSite flags. Now check a site you suspect is older or less secure — you'll often see cookies missing those flags.

🤔 Quick check

Common mistakes

Where people commonly trip up
  • Storing JWTs in localStorage. Every script on the page can read localStorage, including any compromised third-party tag. Put auth tokens in an HttpOnly; Secure; SameSite=Lax cookie instead — JavaScript literally can't see it, so XSS can't exfiltrate it.
  • Mixing up Content-Type and Accept. Content-Type describes what you're sending in the body. Accept describes what you'll receive. Setting Content-Type: application/json on a GET request is meaningless (no body) and won't make the server respond in JSON.
  • Setting SameSite=None "to be safe." None is less safe — it allows cross-site CSRF. It's only needed when you genuinely embed your cookie-bearing endpoint inside someone else's site (third-party widgets). For your own app, Lax is the right default.
  • Treating JWTs as logout-friendly. A JWT is valid until it expires, signature alone. "Logging out" by deleting the token client-side does nothing if a copy already leaked — the server will still accept it. If you need real revocation, use server-side sessions or maintain a deny-list.
  • Forgetting that cookies are sent on every request to the domain. Setting a 4KB cookie means every image, every CSS file, every API call ships those 4KB upstream. Cookies are for identity, not for app state — for app state, use localStorage, IndexedDB, or in-memory.

Quick check

Checkpoint Quiz

Did headers & cookies stick?

Required

What's next

→ Continue to DNS: The Internet's Phone Book where we'll see how google.com actually becomes an IP address.