Skip to content
yutils

SameSite Cookies and CSRF — What Lax, Strict, and None Actually Mean

How SameSite changed CSRF defense in 2020, the differences between Lax/Strict/None, when you need Secure, third-party cookie deprecation, and what's still required beyond SameSite.

~8 min read

When Chrome 80 changed the SameSite default to Lax in 2020, CSRF defense changed forever. Before, almost every form POST without a CSRF token was vulnerable. After, SameSite=Lax alone blocks most cross-site POSTs. This guide explains the exact differences between Lax, Strict, and None, when Secure is required, what the third-party cookie deprecation means, and what defenses you still need beyond SameSite.

The three SameSite values

None — sent in every context

Set-Cookie: token=abc; SameSite=None; Secure
  • Cookie is sent on cross-site requests (fetch from another domain, images, iframes).
  • Secure is required — without HTTPS, browsers ignore SameSite=None.
  • Typical use: third-party widgets (chat, comments, ad tracking).

Lax — safe top-level navigation only

Set-Cookie: token=abc; SameSite=Lax
  • Top-level GET only — cookies are sent when the user clicks a link from another site to yours.
  • Cross-site POST, fetch, iframe, and image-style sub-requests do not carry cookies.
  • The default in every modern browser since 2020.
  • This alone blocks roughly 80% of historical CSRF.

Strict — same site only

Set-Cookie: token=abc; SameSite=Strict
  • Cookies are sent only on requests originating from the same site.
  • Following an external link logs the user out — the cookie doesn't accompany the navigation. Bad UX for users arriving via email or search.
  • Reserve for narrow admin/internal pages where cross-site entry isn't needed.

What "same site" actually means — eTLD+1

The "site" in SameSite is not the host — it's eTLD+1 (effective Top-Level Domain + 1):

  • app.example.com and api.example.com — same site (eTLD+1 = example.com).
  • example.com and example.org — different sites.
  • foo.github.io and bar.github.io — different sites, because github.io is on the Public Suffix List.

The Public Suffix List (PSL) decides. Hosts like github.io and vercel.app are registered there, so their subdomains are cross-site. Split a URL with URL Parser to inspect the eTLD+1 visually.

Don't confuse with CORS origin (scheme + host + port). SameSite is scheme-agnostic and port-agnostic — only eTLD+1 matters.

Lax's POST exception (now mostly gone)

Early in Chrome 80, SameSite=Lax cookies were sent on cross-site POSTs for two minutes after the cookie was set, to accommodate OAuth-style flows. The exception was removed by 2021 — OAuth now uses explicit SameSite=None; Secure or a GET-based redirect.

Third-party cookie deprecation (2024–2025)

Chrome began rolling out third-party cookie blocking in January 2024 (1% → 100%). Safari and Firefox have blocked by default for years.

Impact:

  • Ad tracking — the biggest hit. Privacy Sandbox (Topics API, etc.) is the proposed replacement.
  • SSO / federated identity — Google Sign-In and friends. FedCM (Federated Credential Management) is the alternative.
  • Embedded widgets — Disqus comments, Stripe Checkout, etc. need SameSite=None with explicit user consent, or a redirect flow on their own domain.

For new sites in 2026 — don't depend on third-party cookies. Use redirect flows that land on your own domain.

Other cookie attributes

Secure

Sent only on HTTPS. Required alongside SameSite=None.

HttpOnly

Inaccessible to document.cookie. Closes the "one XSS leaks every token" hole. Auth cookies must be HttpOnly.

__Host- / __Secure- prefixes

  • __Secure-name — only settable on a response with Secure.
  • __Host-name — same plus Path=/ and no Domain attribute. Pinned to exactly one host.

The safest auth cookie:

Set-Cookie: __Host-session=abc; Path=/; Secure; HttpOnly; SameSite=Lax

Drop a Set-Cookie header into Cookie Parser to see exactly how each attribute parses.

Is SameSite enough by itself?

On modern browsers (2020+) with Lax as the default, 99% of cross-site POST/fetch is automatically blocked. But SameSite does not stop every CSRF:

  1. Same-site XSS — an XSS on your own site bypasses SameSite entirely. Pair with CSP.
  2. Subdomain takeover — if blog.example.com is hijacked, it can use example.com's SameSite cookies.
  3. Legacy browsers — old Android and IE don't support SameSite. Low share, but non-zero.
  4. Intentional SameSite=None — for cross-site integrations, SameSite is off by design.

SameSite is the first line. Combine with:

  • CSRF tokens on state-changing requests — hidden input in forms or a custom header. Server validates.
  • Origin / Referer check — lighter. Verify the Origin header matches your domain on POSTs.
  • Double-submit cookie pattern — the cookie value and a header value must match. JS reads the cookie and sets the header.

Real-world pattern — auth cookie + API

# 1. Login response — safest form
Set-Cookie: __Host-session=eyJhbGc...;
  Path=/;
  Secure;
  HttpOnly;
  SameSite=Lax;
  Max-Age=86400

# 2. Subsequent API calls send the cookie automatically
GET /api/me
Cookie: __Host-session=eyJhbGc...

# 3. Attempted cross-site fetch (malicious site)
fetch("https://example.com/api/transfer", {
  method: "POST",
  credentials: "include"
});
# → SameSite=Lax blocks the cookie on POST → 401

A same-site SPA calls the API with credentials: include; cross-site is blocked automatically.

Common pitfalls

1. SameSite=None without Secure

The browser ignores it. The cookie never sets. A common debugging dead-end.

2. SameSite=None on dev (http localhost)

Won't work without Secure. Dev uses SameSite=Lax or omits it. Or temporarily flip the Chrome flag at chrome://flags.

3. Removing CSRF tokens because of SameSite

Same-site XSS defeats SameSite. Keep tokens for high-stakes actions (payments, account changes).

4. Applying Strict broadly

Users arriving via an external link look logged out. SEO and email traffic suffer. Strict only fits a narrow set of contexts.

5. Misunderstanding eTLD+1

api.example.com and app.example.com are the same site — cookies from one are sent to the other. Don't assume they're isolated security contexts.

6. Relying on third-party cookies in 2026

Chrome's deprecation rolls forward. Embedded widgets need a redirect flow; SSO needs FedCM.

7. Reading auth cookies from document.cookie

HttpOnly stops that — by design. Check session status via a separate API like /api/me.

Summary

  • Modern browsers default to SameSite=Lax. Cross-site POST/fetch is blocked automatically.
  • None + Secure for cross-site integrations — increasingly deprecated.
  • Strict breaks entry-from-elsewhere UX — narrow admin pages only.
  • Safest auth cookie = __Host-name; Path=/; Secure; HttpOnly; SameSite=Lax.
  • SameSite is the first defense. Pair with CSP + CSRF tokens + Origin checks for everything important.
  • Third-party cookies are deprecated in 2024–2025. Design new systems for first-party only.
Back to guides