skip to content

Explain what `SameSite=Strict`, `SameSite=Lax` and `SameSite=None` each do to when a browser sends a cookie, and when you would choose each.

level: middleimportance: must knowfreq 65%

answer

  1. same-site = eTLD+1, not same-origin
  2. Strict: nothing cross-site, links look logged out
  3. Lax: cross-site top-level safe-method navigation only
  4. None requires Secure or the cookie is dropped
  5. no protection between your own subdomains

basics

~20 s

SameSite controls whether a cookie rides on cross-site requests. Strict: never on cross-site requests, including top-level links. Lax: only on top-level, safe-method navigations such as clicking a link, not on cross-site POSTs, iframes, images or fetches. None: always sent, and it must also be Secure.

solid answer

~60 s

"Same-site" compares the registrable domain (eTLD+1) of the page initiating the request with that of the request target — it is not the same as same-origin, so `app.example.com` and `api.example.com` are same-site. - **`Strict`**: sent only on same-site requests. Even following a link from another site to yours arrives without the cookie, so the first page looks logged out. Right for cookies guarding state-changing surfaces, or as a second "sensitive action" cookie. - **`Lax`**: sent on same-site requests, plus cross-site **top-level navigations using a safe method** (clicking a link, a GET redirect). Not sent for cross-site POST form submissions, iframes, `<img>`, `<script>`, or `fetch`/XHR. This is the usable default: links from email still work, but a hidden cross-site POST does not carry your session. - **`None`**: sent on every cross-site request. Required for genuine third-party use — embedded widgets, cross-site iframes, some SSO and payment flows. Browsers reject `SameSite=None` unless `Secure` is also present. Default to `Lax` for session cookies; use `None; Secure` only when a cookie must work embedded in someone else's site.

code

http · 3 lines
http
Set-Cookie: sid=abc; Path=/; Secure; HttpOnly; SameSite=Strict
Set-Cookie: sid=abc; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: widget=abc; Path=/; Secure; HttpOnly; SameSite=None

go deeper

for a junior

Give the three modes and one concrete example each — especially that Lax still sends on a clicked link but not on a cross-site POST.

for a middle

Define same-site as eTLD+1, enumerate exactly which request types Lax withholds, and state the None-requires-Secure rule.

for a senior

Argue the CSRF layering — SameSite as defence in depth over tokens — and handle the Strict UX problem with a two-cookie split for sensitive actions.

for a principal

Weigh embedding requirements against exposure across the product estate, and plan for third-party cookie deprecation and partitioning rather than assuming SameSite=None keeps working.

## What "same-site" means `SameSite` compares the **site** of the context initiating the request with the site of the request's target. "Site" here means the registrable domain — the public suffix plus one label (eTLD+1), sometimes with the scheme included ("schemeful same-site") in current browsers. This is deliberately looser than *same-origin*: - `https://app.example.com` → `https://api.example.com` is **same-site** (both `example.com`) but cross-origin. - `https://example.com` → `https://example.org` is cross-site. - With schemeful same-site, `http://example.com` → `https://example.com` counts as cross-site too. So `SameSite` gives you no protection between your own subdomains; it is a cross-*site* control, aimed at requests your site did not initiate. ## The three values **`SameSite=Strict`** — the browser attaches the cookie only when the request is same-site. Any cross-site request, including a plain top-level navigation from a link on another site, arrives without it. Effect: a user clicking your link from a search result, a chat app, or an email lands on a page that renders as logged out, and only appears logged in after a subsequent same-site navigation. That is why Strict is rarely the only session cookie. Common patterns: use Strict for a second, high-value cookie required by sensitive endpoints (change password, transfer money) while a Lax cookie carries ordinary identity; or accept the UX hit on an internal tool. **`SameSite=Lax`** — same-site requests always carry the cookie. Cross-site requests carry it only if **both**: it is a *top-level navigation* (the URL in the address bar changes; not an iframe, image, script, stylesheet, XHR or fetch), **and** the method is "safe" (GET/HEAD, not POST). So: - click a link from another site → cookie sent ✓ - another site's `<form method=POST>` targeting you → cookie **not** sent ✗ - your site embedded in another site's iframe → not sent ✗ - `<img src="https://you/logout">` on another site → not sent ✗ - cross-site `fetch()` with credentials → not sent ✗ That combination kills the classic CSRF shapes (hidden auto-submitting forms, image-tag GET side effects when the cookie is Lax) while keeping inbound links working. **`SameSite=None`** — no restriction; the cookie rides every cross-site request. Browsers require `Secure` alongside it and drop the cookie otherwise. You need `None` when the cookie must function while your site is *embedded in someone else's*: a support-chat widget, an SSO iframe check, an ad or analytics pixel, a payment iframe, some OIDC front-channel flows. Note that `None` alone is no longer sufficient in browsers that partition or block third-party cookies; those contexts increasingly need storage partitioning (CHIPS, i.e. `Partitioned`) or a different design entirely. ## Choosing Start at `Lax` for session cookies — it is also the browser default now, so it is what you get if you say nothing. Move to `Strict` only for cookies whose absence on an inbound link is acceptable or is compensated by a second cookie. Move to `None; Secure` only under a concrete embedded requirement, and treat it as a decision that widens exposure: the cookie now travels on requests any site can trigger, so CSRF defence must come entirely from tokens and header checks. ## Limits worth stating `SameSite` is a browser-enforced heuristic, not a protocol guarantee. Non-browser clients, older browsers, and anything replaying a captured request ignore it. It does not distinguish your own subdomains, so a compromised or hostile subdomain is entirely unaffected by it. It does not protect GET endpoints with side effects against same-site attacks, and under Lax a cross-site *top-level GET* still carries the cookie — so a GET that mutates state remains exploitable by a link. For those reasons `SameSite` is defence in depth, layered on top of proper CSRF tokens (or an equivalent such as requiring a custom header that cross-site forms cannot set), safe-method discipline, and `Secure`/`HttpOnly`.

  • Does SameSite=Lax protect a GET endpoint that changes state?
    Not against a top-level navigation. Lax deliberately sends the cookie on cross-site top-level GET navigations so inbound links work, so a plain link to https://you/delete?id=1 will carry the session. It does block image tags, iframes and fetches. The real fix is to stop mutating state on safe methods.
  • Your session cookie is on example.com and a hostile page exists on a compromised subdomain. Does SameSite help?
    No. SameSite compares registrable domains, so anything under example.com is same-site and requests it initiates carry the cookie normally. Subdomain threats need separate defences: host-only __Host- cookies, origin checks on state-changing endpoints, and not delegating subdomains you do not control.

Strict is a badge that only works if you were already inside the building. Lax also works if you walked in through the front door, but never if something was slipped under the door on your behalf.

saying these in an interview costs you the question

  • Treating same-site as identical to same-origin, so subdomains are assumed isolated
  • Believing SameSite=Lax blocks all cross-site requests including top-level links
  • Setting SameSite=None without Secure and expecting the cookie to be stored
  • Claiming SameSite fully replaces CSRF tokens
  • Choosing Strict for the main session cookie without accounting for inbound links appearing logged out

context