Adam Innes · Blog

Chrome 80 Plans to Make Cookies SameSite=Lax by Default: What Breaks and How to Prepare

· 7 min · security, chrome, cookies, web

For as long as most of us have been writing web apps, a cookie with no special attributes has gone along on every request to its domain, no matter which site started the request. An image on someone else’s page, a form that posts to your login endpoint from another domain, your widget sitting in an iframe on a customer’s site: the browser attaches your cookies to all of it. Chrome is planning to flip that default, and last week Google put a date on it.

I went through Google’s announcements, the Chromium project’s SameSite pages, and the IETF drafts behind the change to figure out what’s actually changing, what it breaks, and what’s worth doing now.

What SameSite does

The SameSite attribute is defined in draft-ietf-httpbis-rfc6265bis-03, the April 2019 revision of the working draft meant to replace the cookie RFC. It lets a server say whether a cookie should be attached to cross-site requests, where “site” means the registered domain, so a request from www.example.com to static.example.com counts as same-site, while a request from your site to a payment provider or an ad network is cross-site.

The draft defines three values. With Strict, the cookie is only sent on same-site requests, which means even clicking a link to your site from somewhere else arrives without it. With Lax, the cookie is also sent on cross-site requests, but only when they’re top-level navigations using a safe method, so following a link with a GET works while a cross-site POST, an image, or a request made from inside an iframe does not. With None, the cookie goes everywhere, the way cookies always have. That explicit None value is new in revision 03; before that, you got the send-everywhere behavior by leaving the attribute off.

Here’s one header per value, written to match the draft’s grammar:

Set-Cookie: sid=31d4d96e407aad42; Path=/; Secure; HttpOnly; SameSite=Strict
Set-Cookie: lang=en-US; Path=/; SameSite=Lax
Set-Cookie: widget_session=abc123; Path=/; SameSite=None; Secure

The draft is also honest about the limits. It says Lax gives reasonable defense in depth against CSRF attacks that rely on unsafe methods like POST, but isn’t a robust defense against CSRF as a whole, because an attacker can still trigger top-level navigations. So SameSite doesn’t retire your CSRF tokens.

The proposal behind the change

In May, Mike West at Google published an individual draft called Incrementally Better Cookies. It proposes two changes on top of rfc6265bis. First, a cookie with no SameSite attribute should be treated as SameSite=Lax, so a plain key=value behaves like key=value; SameSite=Lax, and any unrecognized SameSite value also maps to Lax instead of None. Second, a cookie that asserts SameSite=None must also carry Secure, or it gets rejected outright.

The reasoning is that today developers have to opt into protection, and the draft would rather put the burden on the smaller group of services that really need cross-site state. Requiring Secure on those cookies is aimed at network attackers, and the draft points out a side effect it clearly likes: it pushes embeddable third-party content toward HTTPS. It also notes that this doesn’t stop tracking, since trackers can simply declare SameSite=None, but it does make those cookies easy for browsers to tell apart.

What Google announced, and when

The first announcement came on May 7 at Google I/O. The Chromium blog post that day said Chrome would require developers to explicitly mark which cookies can work across sites, building on SameSite, and that it eventually planned to limit cross-site cookies to HTTPS.

The version number came on October 23 in a second Chromium blog post aimed squarely at developers. Google says Chrome plans to enforce the new model with Chrome 80 in February 2020. From then on, cookies with no declared SameSite value will be treated as Lax, and only cookies set with SameSite=None; Secure will be available in cross-site contexts. The post adds that Mozilla has stated an intent to implement the same requirements in Firefox, and that Microsoft plans to start experimenting with the model in Edge 80. Google revised two of its preparation notes on October 28, so reread it if you saw it early.

Chromium’s SameSite updates page fills in the schedule. As of mid October it listed the experimental behavior going to half of Chrome Canary and Dev users in early October, extending to half of Chrome 79 Beta users when that beta arrives on October 31, and becoming the default on Stable with Chrome 80, which it lists for February 4, 2020. The beta experiment was originally meant for Chrome 78 and was pushed back after feedback from users and enterprise customers. All of this is a plan, and dates can move.

There’s one wrinkle worth knowing about. The same page says that in Chrome 80, cookies with no SameSite attribute will be treated as Lax but will still be included in POST requests, as a temporary “Lax+POST” intervention with a two minute time threshold. Google says it will remove that allowance at some point after Chrome 80 reaches Stable.

What breaks

Anything that depends on a cookie showing up in a cross-site context and doesn’t set SameSite=None; Secure is at risk. The rfc6265bis draft itself calls out embedded content (social networking widgets and commenting services) and some forms of single sign-on as use cases that SameSite doesn’t fit.

Embeds are the obvious one. If your product runs in an iframe on other people’s sites and the session lives in a cookie, that cookie won’t be sent once it’s treated as Lax, because the iframe isn’t a top-level navigation. Users will look logged out inside the embed. The same goes for images, scripts, and fetch calls to your domain from another site that expect a cookie.

Cross-site POST flows are the sneakier case. Federated login protocols that post a response back to your site from an identity provider, and payment flows where a bank or payment page posts the user back to your checkout, both send a top-level cross-site POST. Under strict Lax rules, a cookie without an explicit SameSite value doesn’t come along, so your server can lose track of the session or the state value it was waiting for. The Lax+POST window is exactly why Google suggests testing these flows both quickly and with a delay longer than two minutes. A user who takes three minutes to finish a bank verification is not an exotic case.

Then there’s the Secure requirement. A cookie marked SameSite=None without Secure gets rejected, and the whole point of Secure is that the cookie only travels over HTTPS. Chromium’s updates page warns this may mean upgrading HTTP sites to HTTPS, so an embed or endpoint that still runs on plain HTTP has a bigger job ahead.

The clients that get SameSite=None wrong

This is what makes the fix less mechanical than it sounds. Chromium keeps a list of known incompatible clients. Chrome 51 through 66, which also affects older Chromium-derived browsers and Android WebView, reject a cookie that says SameSite=None, because that value didn’t exist in the spec when they shipped. UC Browser on Android before 12.13.2 does the same. And Safari on macOS 10.14 plus every browser on iOS 12 treats SameSite=None as if it said Strict, which is roughly the opposite of what you asked for. The page says that WebKit bug is fixed in newer iOS and macOS releases.

So setting SameSite=None for everyone can break cross-site cookies for those users today, while not setting it breaks them in Chrome 80. The Chromium page offers pseudocode for skipping the attribute based on the User-Agent string, and recommends a tested User-Agent parsing library over hand-written regular expressions. The Chromium blog also notes that some languages and frameworks don’t support the None value yet, so you may have to write the header yourself.

What I’d do now

Start with an audit. Make a list of every cookie your sites and services set, and for each one decide whether it truly needs to be sent from another site. Session cookies for a normal first-party app usually don’t. Cookies for embeds, SSO, payment return pages, and anything served to other domains usually do.

Then set SameSite explicitly on everything. The Chromium post says purely same-site cookies need no action, but still recommends setting Lax or Strict yourself because not every browser protects them by default, and Google’s SameSite cookies explained article makes the same point. I agree: don’t depend on one browser’s default. For cookies that genuinely need to work cross-site, use SameSite=None; Secure, serve them over HTTPS, and decide how you’ll handle the incompatible clients. If one cookie serves both first-party and cross-site uses, the Chromium post suggests splitting it in two so the first-party one keeps Lax.

Finally, test in Chrome before February. In Chrome 76 and later you can open chrome://flags and enable #same-site-by-default-cookies and #cookies-without-same-site-must-be-secure, then restart. Chromium’s SameSite updates page suggests focusing on federated login, multiple domains, and cross-site embedded content. If something breaks, turning the flags off one at a time tells you whether it’s a missing Secure or a missing SameSite=None. Chrome 77 and later also log DevTools console warnings when a page has cross-site cookies missing the new settings, a quick way to spot vendors that haven’t updated. Enterprise admins get Chrome 79 policies, LegacySameSiteCookieBehaviorEnabledForDomainList and LegacySameSiteCookieBehaviorEnabled, to temporarily keep the old behavior for apps that aren’t ready.

The change itself is small and sensible: cookies should stay home unless you say otherwise. The work is in finding the handful of cookies that were quietly relying on going everywhere, and February isn’t that far off.

← all posts