Chrome,Firefox,Edge,and others are changing their default behavior in line with the IETFproposal,Incrementally Better Cookiesso that:
- Cookies without a
SameSite
attribute are treated asSameSite=Lax
,meaning the default behavior is to restrict cookies to first partycontexts only. - Cookies for cross-site usage must specify
SameSite=None; Secure
toenable inclusion in third party context.
If you haven't already done so, you should update the attributes for yourthird-party cookies so they won't be blocked in the future.
Use cases for cross-site or third-party cookies
There are a number of common use cases and patterns where cookies need to besent in a third-party context. If you provide or depend on one of these usecases, make sure that either you or the provider are updating their cookies tokeep the service functioning correctly.
Content within an <iframe>
Content from a different site displayed in an <iframe>
is in a third-partycontext. Standard use cases include:
- Embedded content shared from other sites, such as videos, maps, code samples,and social posts.
- Widgets from external services such as payments, calendars, booking, andreservation features.
- Widgets such as social buttons or anti-fraud services that create less obvious
<iframes>
.
Cookies may be used here to, among other things, maintain session state, storegeneral preferences, enable statistics, or personalize content for users withexisting accounts.
![SameSite cookie recipes | Articles | web.dev (2) SameSite cookie recipes | Articles | web.dev (2)](https://i0.wp.com/web.dev/static/articles/samesite-cookie-recipes/image/diagram-a-browser-window-809ed902fbce7.png)
Because the web is inherently composable, <iframes>
are also used to embedcontent viewed in a top-level or first-party context. Any cookies the sitedisplayed in the iframe uses are considered third-party cookies. If you'recreating sites that you want other sites to embed, and need cookies to make themwork, you also need to ensure those are marked for cross-site usage or that youcan fall back gracefully without them.
"Unsafe" requests across sites
"Unsafe" might sound concerning here, but it refers to any request that might beintended to change state. On the web, that's primarily POST requests. Cookiesmarked as SameSite=Lax
are sent on safe top-level navigations, like clicking alink to go to a different site. However, something like a <form>
submission toa different site using POST doesn't include cookies.
![SameSite cookie recipes | Articles | web.dev (3) SameSite cookie recipes | Articles | web.dev (3)](https://i0.wp.com/web.dev/static/articles/samesite-cookie-recipes/image/diagram-a-request-moving-46b47373768e3.png)
This pattern is used for sites that can redirect the user out to a remoteservice to perform some operation before returning, for example, redirecting toa third-party identity provider. Before the user leaves the site, a cookie isset containing a single use token with the expectation that this token can bechecked on the returning request to mitigateCross Site Request Forgery (CSRF)attacks. If that returning request comes through POST, you'll need to mark thecookies as SameSite=None; Secure
.
Remote resources
Any remote resource on a page, such as from <img>
tags or <script>
tags,might rely on cookies being sent with a request. Common use cases includetracking pixels and personalizing content.
This also applies to requests sent from your JavaScript using fetch
orXMLHttpRequest
. If fetch()
is called with thecredentials: 'include'
option,those requests are likely to include cookies.For XMLHttpRequest
, expected cookies are usually indicated by awithCredentials
valuefo true
. Those cookies must be appropriately marked to be included incross-site requests.
Content within a WebView
A WebView in a platform-specific app is powered by a browser. Developers need totest whether the restrictions or issues that affect their apps also apply totheir app's WebViews.
Android also lets its platform-specific apps set cookies directly using theCookieManager API.As with cookies set using headers or JavaScript, consider includingSameSite=None; Secure
if they're intended for cross-site use.
How to implement SameSite
today
Mark any cookies that are only needed in a first-party context as SameSite=Lax
or SameSite=Strict
depending on your needs. If you don't mark these cookiesand instead rely on default browser behavior to handle them, they can behaveinconsistently across browsers and potentially trigger console warnings for eachcookie.
Set-Cookie: first_party_var=value; SameSite=Lax
Make sure to mark any cookies needed in a third-party context asSameSite=None; Secure
. Both attributes are required. If you just specifyNone
without Secure
, the cookie will be rejected. To account for differencesin browser implementations, you might need to use some of the mitigatingstrategies described in Handle incompatible clients.
Set-Cookie: third_party_var=value; SameSite=None; Secure
Handle incompatible clients
Because these changes to include None
and update default behavior are stillrelatively new, different browsers handle them in different ways. You can referto the updates page on chromium.orgfor a list of known issues, but this list might not be exhaustive.
One possible workaround is to set each cookie in both the new and the old style:
Set-cookie: 3pcookie=value; SameSite=None; SecureSet-cookie: 3pcookie-legacy=value; Secure
Browsers implementing the newer behavior set the cookie with the SameSite
value. Browsers that don't implement the new behavior ignore that value and setthe 3pcookie-legacy
cookie. When processing included cookies, your site shouldfirst check for the presence of the new style of cookie and, then fall back tothe legacy cookie if it can't find a new one.
The following example shows how to do this in Node.js, using theExpress framework and itscookie-parser middleware:
const express = require('express');const cp = require('cookie-parser');const app = express();app.use(cp());app.get('/set', (req, res) => { // Set the new style cookie res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true }); // And set the same value in the legacy cookie res.cookie('3pcookie-legacy', 'value', { secure: true }); res.end();});app.get('/', (req, res) => { let cookieVal = null; if (req.cookies['3pcookie']) { // check the new style cookie first cookieVal = req.cookies['3pcookie']; } else if (req.cookies['3pcookie-legacy']) { // otherwise fall back to the legacy cookie cookieVal = req.cookies['3pcookie-legacy']; } res.end();});app.listen(process.env.PORT);
This approach requires you to do extra work setting redundant cookies and makingchanges at the point of both setting and reading the cookie. However, it shouldcover all browsers regardless of their behavior, and keep third-party cookiesfunctioning.
As an alternative, you can detect the client using the user agent string when aSet-Cookie
header is sent. Refer to thelist of incompatible clients,and use an appropriate user agent detection library for your platform, forexample, the ua-parser-js libraryon Node.js. This approach only requires you to make one change, but user agentsniffing might not catch all affected users.
Support for SameSite=None
in languages, libraries, and frameworks
The majority of languages and libraries support the SameSite
attribute forcookies. However, because the addition of SameSite=None
is still relativelyrecent, you might need to work around some standard behavior for now.These behaviors are documented in theSameSite
examples repository on GitHub.
Getting help
Cookies are used everywhere on the web, and it's rare for any development teamto have complete knowledge of where their site sets and uses them, especiallyin cross-site use cases. When you encounter an issue, it might be the first timeanyone has encountered it, so don't hesitate to reach out:
- Raise an issue in the
SameSite
examples repository on GitHub. - Ask a question in the"samesite" tag on StackOverflow.
- For issues with Chromium's behavior, raise a bug in theChromium issue tracker.
- Follow Chrome's progress on the
SameSite
updates page.