Cookie attribute
< Set-Cookie: id=a3fWa; SameSite=LaxSameSite Cookie Attribute: Strict, Lax and None
How SameSite works: Strict, Lax and None, what counts as same-site, why Lax-by-default is Chromium behavior, and how to fix cookies blocked cross-site.
- Default if omitted
- Lax in Chromium (Lax-by-default); other browsers vary
- Accepts
- Strict, Lax or None (None requires Secure)
- Sent back to server
- No: never echoed in the Cookie header
On this page
TL;DR:
SameSitedecides whether a cookie rides along on requests that start from another site. Set it explicitly:Laxfor session cookies,Strictfor high-risk ones,None; Secureonly for cookies that must work inside third-party embeds. The “unset means Lax” default is Chromium-only.
Same-site is not same-origin
The most common SameSite confusion is the definition of “site”. A site is the scheme plus the registrable domain (eTLD+1, computed with the Public Suffix List). Port and subdomain do not matter.
| Request from | To | Same-site? |
|---|---|---|
https://app.example.com | https://api.example.com | Yes (both example.com) |
https://example.com:3000 | https://example.com:8443 | Yes (ports ignored) |
https://example.com | https://example.org | No |
http://example.com | https://example.com | No in Chrome and Edge (schemeful same-site, Chrome 89+); other browsers have not matched this consistently, so do not rely on it |
https://alice.github.io | https://bob.github.io | No (github.io is on the Public Suffix List) |
So a frontend on app.example.com calling api.example.com sends SameSite=Strict cookies fine, while the same frontend calling api.example.net does not, even though CORS is configured correctly. CORS and SameSite are independent checks; see CORS vs CSP and the CORS guide.
The three values
| Value | Cross-site top-level link (GET) | Cross-site POST form | fetch / XHR / iframe / img |
|---|---|---|---|
Strict | Not sent | Not sent | Not sent |
Lax | Sent | Not sent | Not sent |
None | Sent | Sent | Sent (requires Secure) |
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly; Path=/
Strict has a UX cost: a user who clicks a link to your site from an email or chat arrives without the cookie, so the first page renders logged out. Typical workaround is a Lax session cookie plus a Strict cookie only for sensitive actions, or a redirect hop that re-requests the page from same-site context.
Browser differences
| Behavior | Chrome / Edge | Firefox | Safari |
|---|---|---|---|
Missing SameSite treated as Lax | Yes (since Chrome 80) | No | No |
| “Lax+POST” exception for unmarked cookies younger than 2 minutes | Yes | Not applicable | Not applicable |
SameSite=None requires Secure | Yes (enforced alongside Lax-by-default) | Not enforced by default; the requirement is in RFC 6265bis | Not enforced; Safari 12 and macOS 10.14’s Safari 13 treat None as Strict, fixed in 10.15 and later |
| Third-party cookies | Still allowed by default as of this review; Partitioned (CHIPS) available | Blocked or partitioned by Total Cookie Protection | Blocked by Intelligent Tracking Prevention |
Treat the table as a snapshot: third-party cookie policy has changed repeatedly, and Firefox and Safari restrictions apply even to cookies with SameSite=None. The practical rule is the same everywhere: if your feature needs a cookie in a cross-site iframe, test in all three browsers and plan for Partitioned cookies or the Storage Access API instead.
The Lax+POST exception exists only in Chromium and only for cookies with no explicit SameSite attribute that were set less than two minutes ago. It was a migration aid for SSO flows that POST back to the relying party. Do not depend on it; set SameSite=None; Secure explicitly if you need cross-site POST.
Console messages and what they mean
| Browser message | Cause |
|---|---|
Cookie "x" has been rejected because it is in a cross-site context and its "SameSite" is "Lax" or "Strict" (Firefox) | A cross-site request tried to set or send a Lax/Strict cookie |
This Set-Cookie was blocked because it had the "SameSite=None" attribute but did not have the "Secure" attribute (Chrome) | Add Secure and serve over HTTPS |
This attempt to set a cookie via a Set-Cookie header was blocked because it had the "SameSite=Strict" or "SameSite=Lax" attribute but came from a cross-site response (Chrome) | Cross-site fetch response set a Lax/Strict cookie; use None; Secure or restructure |
Reproduce what the server sends before debugging the browser:
curl -sI https://example.com/login | grep -i '^set-cookie'
Fix: cookie missing in an embed or cross-site API
// Express: cross-site API called from another registrable domain
res.cookie('session', token, {
sameSite: 'none',
secure: true,
httpOnly: true,
partitioned: true // CHIPS: separate jar per top-level site; Chromium and Firefox
})
# Django settings.py
SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True
# Flask
app.config.update(SESSION_COOKIE_SAMESITE='None', SESSION_COOKIE_SECURE=True)
On the client the request must also opt in: fetch(url, { credentials: 'include' }), and the server must send Access-Control-Allow-Credentials: true with a specific (non-*) Access-Control-Allow-Origin.
OAuth and SSO redirects
When an identity provider redirects back to your callback, that is a cross-site top-level GET navigation. A Strict session cookie is not sent, so the callback sees no session. Lax works for this flow. If the provider returns the result with a form_post response mode (cross-site POST), even Lax cookies are withheld; the state cookie for that callback needs SameSite=None; Secure with a short Max-Age.
SameSite does not replace CSRF tokens
Lax still allows cross-site GET navigations, and requests from sibling subdomains such as evil.example.com to app.example.com are same-site. Keep CSRF tokens (or Sec-Fetch-Site checks) for state-changing endpoints, and never mutate state on GET.
Related
Frequently asked questions
What is the SameSite cookie attribute?
SameSite tells the browser whether to attach a cookie to requests that start from a different site than the cookie belongs to. It is the main browser-side defense against cross-site request forgery, but it is defense in depth and does not replace CSRF tokens.
What is the difference between SameSite Strict and Lax?
Strict never sends the cookie on any cross-site request, including a top-level navigation from a link on another site. Lax sends it on top-level navigations that use a safe method such as GET, but not on cross-site POST, fetch, XHR, iframe or image requests.
What is the default SameSite value?
Chrome and Edge (Chromium) treat a cookie with no SameSite attribute as Lax. Firefox and Safari do not apply Lax-by-default, so an unmarked cookie behaves as if it were None there, subject to their separate third-party cookie blocking. Always set SameSite explicitly instead of relying on the default.
Why is my SameSite=None cookie rejected?
Browsers that implement the rule reject SameSite=None unless the cookie also has the Secure attribute, and Secure cookies are only accepted from HTTPS pages (or localhost). Chrome logs "This Set-Cookie was blocked because it had the SameSite=None attribute but did not have the Secure attribute".
Is localhost the same site as 127.0.0.1?
No. Hosts are compared by registrable domain, and an IP address or a bare hostname like localhost is its own site, so localhost:3000 and localhost:8080 are same-site (ports are ignored) but localhost and 127.0.0.1 are cross-site.
Sources
Related
CSRF (Cross-Site Request Forgery)
CSRF tricks a logged-in browser into sending an unwanted request to your site. See how it works, why CORS does not stop it and which defenses actually do.
Same-Site vs Same-Origin
Site and origin are not the same. Learn how eTLD+1 and the Public Suffix List define same-site, and why it decides SameSite cookie and CORS behavior.
Partitioned Cookies (CHIPS): The Partitioned Attribute
The Partitioned cookie attribute (CHIPS) gives third-party embeds a separate cookie jar per top-level site. Syntax, Secure requirement, and browser support.
Cookie Security: HttpOnly, SameSite, and Secure Flags
A comprehensive guide to understanding and implementing secure HTTP cookies to protect against XSS, CSRF, and session hijacking attacks.