Updated April 2026

SameSite Cookie Attribute

Quick Answer

SameSite controls when a cookie is sent with cross-site requests. Strict — never sent cross-site. Lax — sent on top-level navigation only (browser default since Chrome 80). None — always sent, requires Secure.

What SameSite does

Without SameSite, cookies are sent with every request to a domain — including requests initiated by other sites. This enables Cross-Site Request Forgery (CSRF) attacks. SameSite restricts when browsers include cookies in cross-site requests.

The three values

ValueWhen cookie is sentUse case
StrictSame-site requests only. Never cross-site — even clicking a link from another site.Session cookies for banking, admin panels. Highest protection.
LaxSame-site requests + top-level cross-site navigation (GET only). Not sent on cross-site POST, iframes, AJAX.Most web apps. Browser default since Chrome 80.
NoneAll requests, including cross-site. Requires Secure flag.Third-party cookies, OAuth flows, embedded widgets, cross-site auth.

SameSite=Lax — what actually gets blocked

Lax blocks the cookie on cross-site:

Lax allows the cookie on cross-site:

SameSite=None — requires Secure

Browsers reject SameSite=None without Secure. The cookie must also be sent over HTTPS. Chrome enforces this since version 80.

Set-Cookie: session=abc123; SameSite=None; Secure; HttpOnly
If your app uses SameSite=None without Secure, browsers silently drop the cookie. This is a common cause of auth failures in cross-site OAuth flows.

How to set SameSite in each stack

Nginx

add_header Set-Cookie "session=VALUE; SameSite=Lax; Secure; HttpOnly; Path=/" always;

Express

res.cookie('session', value, {
  sameSite: 'lax',   // 'strict' | 'lax' | 'none'
  secure: true,
  httpOnly: true
});

FastAPI / Starlette

response.set_cookie(
    key="session",
    value=value,
    samesite="lax",   # "strict" | "lax" | "none"
    secure=True,
    httponly=True
)

Django

# settings.py
SESSION_COOKIE_SAMESITE = 'Lax'   # 'Strict' | 'Lax' | 'None'
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True

CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = True

Laravel

# config/session.php
'same_site' => 'lax',   // 'strict' | 'lax' | 'none'
'secure' => true,

Browser default — SameSite=Lax

Since Chrome 80 (February 2020), cookies without an explicit SameSite attribute are treated as SameSite=Lax. Firefox and Safari followed. If your app depended on cookies being sent cross-site without SameSite=None, it broke in 2020.

SameSite vs CSRF tokens

SameSite=Strict or Lax provides CSRF protection for most use cases. However it is not a complete replacement for CSRF tokens because: it does not protect against attacks from the same site, some older browsers do not support it, and Lax allows cross-site GET requests which can be exploited in some cases. Use both for defense in depth.

Debugging SameSite issues

Chrome DevTools → Application → Cookies shows the SameSite value for each cookie. The Network tab shows whether cookies were included in specific requests. Missing cookies on cross-site requests is almost always a SameSite or Secure flag issue.

📚 HttpFixer Blog — fix guides, explainers, and references →