Choosing the Right SameSite Value for Cross-Site Cookies in Chrome
A decision guide for picking SameSite=Lax, Strict, or None for cross-site cookies in Chrome, with a comparison table, explicit Set-Cookie examples, and DevTools validation steps.
03 Apr 2026, 21:15 UTC

If your application sets cookies that must travel with cross-site requests — embedded widgets, third-party identity providers, payment redirects — you have to pick a SameSite value, and the wrong pick either breaks the flow silently or weakens CSRF protection. The decision comes down to three supported values: Lax, Strict, and None. This guide compares them against the constraints that matter on current Chrome versions: working behavior, security, and not breaking existing users.
The constraints
Since Chrome 80, any cookie set without an explicit SameSite attribute is treated as SameSite=Lax. That default has been stable for years, but it changed the baseline: code written before 2020 that assumed cookies always flow cross-site may already be broken or may be one redirect away from breaking. Your constraints are typically:
- The cookie must be sent on the requests your flow actually makes (top-level navigation, cross-site POST, subresource fetch, iframe).
- Chrome must accept the cookie —
NonewithoutSecureis rejected outright. - You should not widen cookie exposure beyond what the flow needs, because SameSite is a real CSRF mitigation.
Comparing the three values
| Value | Sent on same-site requests | Sent on cross-site top-level GET navigation | Sent on cross-site POST / fetch / iframe | Requirements | Typical use |
|---|---|---|---|---|---|
Strict | Yes | No | No | None | Highly sensitive actions (e.g., changing payment details) where any cross-site context is suspect |
Lax (Chrome default) | Yes | Yes | No | None | Session cookies for standard browsing; good CSRF baseline |
None | Yes | Yes | Yes | Secure attribute mandatory; HTTPS only | Embedded iframes, SSO callbacks, third-party widgets that genuinely need cross-site state |
Trade-offs that decide the answer
Start from Lax. It covers the most common legitimate cross-site pattern — a user clicking a link into your site — because top-level GET navigations still carry the cookie. It blocks the classic CSRF vector (a cross-site POST form or fetch) without any extra tokens. For most first-party session cookies, Lax is the correct end state, not a compromise.
Strict is for defense in depth, not general sessions. Strict omits the cookie even when the user clicks a link from another site, so a user arriving from an email or a search result appears logged out until they navigate within your site. That is usually unacceptable UX. Reserve Strict for a second, narrowly scoped cookie guarding sensitive operations, paired with a Lax session cookie for everything else.
None is opt-in and conditional. Chrome discards SameSite=None cookies that lack the Secure attribute — the cookie simply never gets stored, which surfaces as mysteriously missing sessions. Every None cookie must be served over HTTPS, and you should treat each one as an explicit exception with a documented reason, because it re-enables cross-site sending that CSRF defenses otherwise rely on. If you use None for an authenticated cookie, keep a separate CSRF token mechanism in place.
Concrete implementation
Set the attributes explicitly rather than relying on defaults — explicit values survive future default changes and behave consistently across browsers. An example response header set for an SSO flow:
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: sso_state=xyz789; Path=/; Secure; HttpOnly; SameSite=None
Set-Cookie: prefs=dark; Path=/; Secure; SameSite=LaxNote that sso_state carries both None and Secure; omitting Secure causes Chrome to reject the cookie entirely. HttpOnly is unrelated to SameSite but should accompany any session cookie.
Validating the behavior
You can verify the decision without guessing:
- Serve a small test page over HTTPS that sets one cookie of each type via
Set-Cookieheaders. - From a page on a different origin, trigger a cross-site
fetchwithcredentials: 'include'and a top-level link navigation. - Open Chrome DevTools (F12) → Network tab → select the request → inspect the Request Headers. Expected result: the fetch carries only the
None; Securecookie; the top-level navigation carriesLaxandNonebut notStrict. - Check the Console and the Application → Cookies panel. Chrome logs a warning when
SameSite=Noneis set withoutSecure; no warning and the cookie visible in the panel confirms acceptance.
DevTools also marks blocked cookies in the Network tab with a warning icon and a hover explanation, which is the fastest way to diagnose "cookie not sent" reports.
Limitations and caveats
SameSite semantics are defined per-site (registrable domain plus scheme in modern "schemeful" handling), not per-origin — app.example.com to api.example.com is same-site. Behavior described here reflects Chrome 80 through current stable releases; verify against your target version, since Chrome has tightened defaults before and may again. Other browsers implement SameSite with subtle differences (notably around the Lax grace periods and default handling), so a configuration validated only in Chrome is not fully validated. If you must support older clients that mishandle None, the historical workaround is user-agent sniffing to omit the attribute for those clients — treat that as technical debt, not a design.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.