SameSite Attribute: Visual Guide
The SameSite attribute controls when cookies are sent with cross-site requests. Understanding this behavior is crucial for web security and proper cookie management.
Overview
The SameSite attribute has three possible values:
SameSite=None: Cookie is sent with all requests, including cross-site (requiresSecure)SameSite=Lax: Cookie is sent with same-site requests and cross-site top-level GET navigations (default)SameSite=Strict: Cookie is only sent with same-site requests (most restrictive)
Same-Site Requests
When a request is made to the same domain where the cookie was set, it's considered a same-site request. In this case, cookies are sent regardless of the SameSite attribute value.
Same-Site Request Flow
Explanation:
- User is on
site-a.com(shown in address bar) - Makes a request to
site-a.com(same domain where cookie was set) - Cookie
promo_shown=1set onsite-a.comIS sent - Works for any HTTP method (GET, POST, etc.)
- Works for any request type (navigation, AJAX, iframe, etc.)
- Key point: Cookie is always sent with same-site requests regardless of
SameSitevalue (None, Lax, or Strict)
Cross-Site Requests
When a request is made to a different domain than where the cookie was set, it's considered a cross-site request. The behavior depends on the SameSite attribute value.
Cross-Site Request Flow (General)
Explanation:
- User is on
site-b.com(shown in address bar) - Makes a request to
site-a.comwhere cookiepromo_shown=1was set - This is a cross-site request because
site-b.com≠site-a.com - Cookie behavior depends on
SameSiteattribute and request characteristics - General rule: Cross-site requests do NOT send cookies unless specific conditions are met
SameSite=Lax Behavior
SameSite=Lax is the default value in modern browsers. It provides a balance between security and usability.
Case 1: Safe Cross-Site GET with Top-Level Navigation
Explanation:
- User is on
site-b.com(shown in address bar) - User clicks a link to
site-a.com(top-level navigation - URL bar changes) - Request uses GET method
- Result: Cookie
promo_shown=1withSameSite=LaxIS sent - Why: Top-level GET navigation is considered "safe" - user-initiated navigation
- Use case: User clicks email link, follows redirect, clicks link from external site
Example:
<!-- User on site-b.com -->
<a href="https://site-a.com/products">Visit Shop</a>
<!-- User clicks link -->
<!-- Cookie IS sent to site-a.com -->
Case 2: Safe Cross-Site GET without Navigation
Explanation:
- User is on
site-b.com(shown in address bar) - Makes GET request to
site-a.comvia AJAX, iframe, image, etc. - Not top-level navigation - URL bar stays the same
- Result: Cookie
promo_shown=1withSameSite=LaxNOT sent - Why: Embedded resources are not considered "safe" navigation - could be used for tracking
- Use case: Tracking pixels, embedded widgets, AJAX calls from different domains
Examples:
<!-- User on site-b.com -->
<img src="https://site-a.com/pixel.gif">
<iframe src="https://site-a.com/widget"></iframe>
<script>
fetch('https://site-a.com/api/data');
</script>
<!-- Cookie NOT sent in any of these cases -->
Case 3: Unsafe Methods
Explanation:
- User is on
site-b.com(shown in address bar) - Makes POST, PATCH, PUT, or DELETE request to
site-a.com - These are "unsafe" methods (can modify server state)
- Result: Cookie
promo_shown=1withSameSite=LaxNOT sent - Why: Protects against CSRF attacks - prevents malicious sites from making authenticated state-changing requests
- Use case: Form submissions, API calls that modify data
Examples:
<!-- User on site-b.com -->
<form method="POST" action="https://site-a.com/login">
<input name="username" value="user">
<button type="submit">Login</button>
</form>
<!-- Cookie NOT sent -->
// User on site-b.com
fetch('https://site-a.com/api/order', {
method: 'POST',
body: JSON.stringify({ items: [...] })
});
// Cookie NOT sent
Unified SameSite Decision Tree
This comprehensive diagram shows how all SameSite values behave across different scenarios:
Explanation:
- Same-site requests: Always send cookies regardless of
SameSitevalue - SameSite=None: Sends cookies with all cross-site requests, but requires
Secureattribute - SameSite=Lax: Only sends cookies with cross-site top-level GET navigation
- SameSite=Strict: Never sends cookies with cross-site requests
Comparison Table
| Scenario | Same-Site? | Top-Level? | Method | SameSite=None | SameSite=Lax | SameSite=Strict |
|---|---|---|---|---|---|---|
User on site-a.com navigates to site-a.com/products |
✅ Yes | N/A | Any | ✅ Sent | ✅ Sent | ✅ Sent |
User on site-b.com clicks link to site-a.com |
❌ No | ✅ Yes | GET | ✅ Sent | ✅ Sent | ❌ Not sent |
User on site-b.com has iframe loading site-a.com |
❌ No | ❌ No | GET | ✅ Sent | ❌ Not sent | ❌ Not sent |
User on site-b.com POSTs form to site-a.com |
❌ No | ✅ Yes | POST | ✅ Sent | ❌ Not sent | ❌ Not sent |
User on site-b.com makes AJAX GET to site-a.com |
❌ No | ❌ No | GET | ✅ Sent | ❌ Not sent | ❌ Not sent |
Legend:
- ✅ Sent: Cookie is sent with request
- ❌ Not sent: Cookie is not sent with request
Detailed Scenarios
Scenario 1: Same-Site Request
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=Lax - User on:
site-a.com - Request to:
site-a.com/products
Flow:
Result: Cookie IS sent (same-site request)
Scenario 2: Cross-Site GET Navigation (Lax)
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=Lax - User on:
site-b.com - Request to:
site-a.com(via link click)
Flow:
Result: Cookie IS sent because:
- ✅ Domain matches: Request is to
site-a.com(matches cookie'sDomain=site-a.com) - ✅ SameSite=Lax allows: Cross-site top-level GET navigation is permitted by Lax
Scenario 3: Cross-Site Embedded Resource (Lax)
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=Lax - User on:
site-b.com - Request to:
site-a.com(via iframe)
Flow:
Result: Cookie NOT sent (embedded resource, not top-level navigation)
Scenario 4: Cross-Site POST (Lax)
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=Lax - User on:
site-b.com - Request to:
site-a.com(via POST form)
Flow:
Result: Cookie NOT sent (cross-site POST, unsafe method)
Scenario 5: Cross-Site Request (Strict)
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=Strict - User on:
site-b.com - Request to:
site-a.com(any method)
Flow:
Result: Cookie NOT sent (cross-site request blocked by Strict)
Scenario 6: Cross-Site Request (None)
Setup:
- Cookie:
promo_shown=1; Domain=site-a.com; SameSite=None; Secure - User on:
site-b.com - Request to:
site-a.com(any method)
Flow:
Result: Cookie IS sent (SameSite=None allows all cross-site requests)
Security Implications
SameSite=None
Security Level: Lowest
- Allows all cross-site requests
- Requires
Secureattribute (HTTPS only) - Used for third-party cookies, tracking, embedded widgets
- Risk: Vulnerable to CSRF attacks if not properly protected
SameSite=Lax
Security Level: Moderate (Default)
- Blocks cross-site POST requests (CSRF protection)
- Blocks cross-site embedded resources (privacy protection)
- Allows cross-site GET navigation (user experience)
- Risk: Still vulnerable to GET-based CSRF if endpoints have side effects
SameSite=Strict
Security Level: Highest
- Blocks all cross-site requests
- Maximum CSRF protection
- Maximum privacy protection
- Risk: May break user experience (users need to re-authenticate when coming from external links)
Best Practices
When to Use SameSite=None
- Third-party widgets/embeds
- Cross-site tracking (be aware of browser restrictions)
- Cross-site POST operations needed
- Always use with
Secureattribute
Example:
Set-Cookie: widget_session=abc; Domain=widget.example.com; SameSite=None; Secure
When to Use SameSite=Lax
- Authentication cookies (most common use case)
- Session management
- General web applications
- Default choice for most cookies
Example:
Set-Cookie: session=abc123; Domain=example.com; SameSite=Lax; Secure; HttpOnly
When to Use SameSite=Strict
- Sensitive operations (banking, healthcare)
- Maximum security requirements
- Can tolerate users needing to re-authenticate
Example:
Set-Cookie: auth_token=xyz; Domain=bank.example.com; SameSite=Strict; Secure; HttpOnly
Summary
Key Points
- Same-site requests: Cookies are always sent regardless of
SameSitevalue - SameSite=None: Cookies sent with all cross-site requests (requires
Secure) - SameSite=Lax: Cookies sent with cross-site top-level GET navigation only
- SameSite=Strict: Cookies sent with same-site requests only
Quick Reference
| SameSite Value | Same-Site | Cross-Site GET Navigation | Cross-Site POST | Cross-Site Embedded |
|---|---|---|---|---|
| None | ✅ Sent | ✅ Sent | ✅ Sent | ✅ Sent |
| Lax | ✅ Sent | ✅ Sent | ❌ Not sent | ❌ Not sent |
| Strict | ✅ Sent | ❌ Not sent | ❌ Not sent | ❌ Not sent |
Decision Guide
Use SameSite=None if:
- You need third-party cookies
- You need cross-site POST operations
- You're building embedded widgets
Use SameSite=Lax if:
- You want CSRF protection with good UX
- You're building general web applications
- You want cookies for cross-site navigation
Use SameSite=Strict if:
- You need maximum security
- You're handling sensitive data
- You can tolerate users re-authenticating
Related Topics
- Learn about Cookie Attributes for complete attribute overview
- Understand SameSite=Lax in detail
- Review Same-Site vs Cross-Site Requests for request classification
- Explore Cross-Domain Behavior for subdomain scenarios
- Read about First-Party vs Third-Party cookies