BizTechLab

IDEASINNOVATIONIMPACT

Web APIs

HTTP Cookies

The original client-side storage — small, automatically sent with every request, and still how a stateless protocol remembers you.

2 August 20268 min read

Overview

are small key-value pairs that the browser automatically attaches to every HTTP request sent to the domain that set them. Cookies predate localStorage by roughly two decades, and they remain the only client-side storage mechanism a server can both set and read directly through plain HTTP headers — no JavaScript required on either side.

Why It Exists

HTTP itself is stateless — by design, a server has no memory of any previous request from the same browser. Cookies exist specifically to bridge that gap: they're how a server recognizes 'this is the same browser that logged in five minutes ago' without inventing some other out-of-band mechanism. Every other client-storage technology that came after — localStorage, IndexedDB — exists on the client only; cookies are the one storage mechanism built into the request/response cycle itself.

Real World Example

After a successful login, a server responds with a `Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax` header. From that point on, every request the browser makes to that same domain automatically includes `Cookie: session_id=abc123` — the client does nothing extra, and the server looks up the session on every request without needing any client-side code to remember and resend a token.

Example Data

Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600

AttributeValueEffect
Name/Valuesession_id=abc123The actual data being stored
HttpOnly(flag)JavaScript cannot read this cookie at all
Secure(flag)Only sent over HTTPS, never plain HTTP
SameSiteLaxNot sent on most cross-site requests
Max-Age3600Expires automatically after 1 hour

Cookie Attributes, One at a Time

HttpOnly

Blocks client-side JavaScript from reading the cookie's value entirely — `document.cookie` simply won't show it. This is the single most effective defense against session-token theft via XSS: even if an attacker injects a script into your page, that script has no way to read an HttpOnly cookie and exfiltrate it.

Set-Cookie: session_id=abc123; HttpOnly

Secure

Tells the browser to only ever send this cookie over HTTPS, never plain HTTP. Without it, a cookie set on a secure page could still leak in cleartext if any part of the site is ever loaded over an unencrypted connection.

Set-Cookie: session_id=abc123; Secure

SameSite

StrictLaxNone

Controls whether the cookie is sent along with cross-site requests — the main defense against CSRF. `Strict` never sends it cross-site (safest, but breaks some legitimate flows like clicking a link from an email). `Lax` sends it on top-level navigation but not on cross-site subrequests (the modern default, and the right choice for most cookies). `None` sends it everywhere, but requires `Secure` and is meant specifically for legitimate cross-site use cases like embedded widgets.

Set-Cookie: session_id=abc123; SameSite=Lax

Domain & Path

Domain controls which hosts the cookie is sent to (omitting it scopes the cookie to the exact host that set it; setting it explicitly, e.g. `.example.com`, shares it across subdomains). Path further scopes it to a specific URL prefix, so a cookie set with `Path=/admin` is never sent on requests to `/checkout`.

Set-Cookie: session_id=abc123; Domain=.example.com; Path=/

Expires & Max-Age

Without either, a cookie is a 'session cookie' — deleted when the browser closes. `Max-Age` (in seconds) or `Expires` (an absolute date) makes it persistent, surviving browser restarts until that time is reached or it's explicitly cleared.

Set-Cookie: session_id=abc123; Max-Age=3600

Diagram

A cookie set once, sent automatically on every request after that

Server responds

Set-Cookie: session_id=abc123

Browser stores it

scoped by domain, path, and attributes

Every future request

Cookie: session_id=abc123 — sent automatically

Server reads it

no client-side code required

Syntax

// Setting a cookie via an HTTP response header (server-side)
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600

// Reading non-HttpOnly cookies client-side
document.cookie; // "theme=dark; consent=true" — a raw, semicolon-separated string

// Setting a non-HttpOnly cookie client-side
document.cookie = "theme=dark; Max-Age=31536000; Path=/";

Common Mistakes

Manually parsing the raw document.cookie string with a naive split(';')

Why: The cookie string format has quoting and encoding edge cases a naive split gets wrong — values containing certain characters can silently corrupt the parse.

Fix: Use a well-tested cookie-parsing library, or your framework's built-in cookie utilities, instead of hand-rolled string splitting.

Leaving a session or auth cookie without the HttpOnly flag

Why: Without it, any XSS vulnerability on the page can read the cookie directly via JavaScript and exfiltrate it — the exact same theft vector that makes localStorage unsafe for tokens.

Fix: Mark every authentication-related cookie HttpOnly so it's simply invisible to JavaScript, XSS included.

Not setting SameSite explicitly and assuming the browser default is correct

Why: Default behavior has changed across browser versions, and a cookie genuinely needed for a cross-site flow (an embedded widget, a third-party integration) can silently stop working if the default doesn't match what the use case actually needs.

Fix: Set SameSite deliberately on every cookie — Lax for most site cookies, None + Secure only for cookies with a real cross-site requirement.

Interview Questions

beginner

What's the core difference between a cookie and localStorage?

A cookie is automatically sent with every matching HTTP request and can be set directly by the server via a response header. localStorage is purely client-side — nothing in it is ever sent to the server automatically, and only JavaScript can read or write it.

intermediate

What does the HttpOnly flag protect against, and what doesn't it protect against?

HttpOnly stops client-side JavaScript from reading the cookie, which neutralizes token theft via XSS. It does nothing against CSRF — a forged cross-site request still automatically carries the cookie, since the browser attaches it regardless of which page triggered the request. SameSite is the mitigation for that, not HttpOnly.

senior

A cookie needs to be shared with a third-party iframe embedded on other sites, but a security review flags it. What's the trade-off?

Sharing a cookie with a cross-site embed requires SameSite=None, which also mandates Secure. But setting SameSite=None deliberately gives up the CSRF protection that Lax or Strict would have provided, so that cookie now needs its own explicit CSRF defense — typically a separate CSRF token validated server-side — rather than relying on SameSite to do that job.

Production Best Practices

Do

Mark every authentication or session cookie HttpOnly and Secure.

Set SameSite explicitly on every cookie instead of relying on the browser's default.

Scope cookies as narrowly as possible with Domain and Path.

Don't

Don't parse document.cookie by hand — use a real cookie-parsing utility.

Don't set SameSite=None unless there's a genuine cross-site requirement, and always pair it with Secure.

Don't store anything larger than a small token in a cookie — every cookie is resent on every matching request, so size is a real bandwidth cost.

Comparison

Blocks JS AccessRequires HTTPSSent Cross-Site
HttpOnlyYesNoDepends on SameSite
SecureNoYesDepends on SameSite
SameSite=StrictNoNoNever
SameSite=LaxNoNoTop-level navigation only
SameSite=NoneNoYes (required)Always

Related Articles