Archived: SameSite cookies explained

This is a simplified archive of the page at https://web.dev/samesite-cookies-explained/

Use this page embed on your own site:

Learn how to mark your cookies for first-party and third-party usage with the SameSite attribute. You can enhance your site's security by using SameSite's Lax and Strict values to improve protection against CSRF attacks. Specifying the new None attribute allows you to explicitly mark your cookies for cross-site usage.

ReadArchived

Secure your site by learning how to explicitly mark your cross-site cookies.

— Updated

On this page

Each cookie contains a key-value pair along with a number of attributes that control when and where that cookie is used.

The introduction of the SameSite attribute (defined in RFC6265bis) allows you to declare if your cookie should be restricted to a first-party or same-site context. It's helpful to understand exactly what 'site' means here. The site is the combination of the domain suffix and the part of the domain just before it. For example, the www.web.dev domain is part of the web.dev site.

The public suffix list defines this, so it's not just top-level domains like .com but also includes services like github.io. That enables your-project.github.io and my-project.github.io to count as separate sites.

Introducing the SameSite attribute on a cookie provides three different ways to control this behaviour. You can choose to not specify the attribute, or you can use Strict or Lax to limit the cookie to same-site requests.

If you set SameSite to Strict, your cookie will only be sent in a first-party context. In user terms, the cookie will only be sent if the site for the cookie matches the site currently shown in the browser's URL bar. So, if the promo_shown cookie is set as follows:

Set-Cookie: promo_shown=1; SameSite=Strict

When the user is on your site, then the cookie will be sent with the request as expected. However when following a link into your site, say from another site or via an email from a friend, on that initial request the cookie will not be sent. This is good when you have cookies relating to functionality that will always be behind an initial navigation, such as changing a password or making a purchase, but is too restrictive for promo_shown. If your reader follows the link into the site, they want the cookie sent so their preference can be applied.

That's where SameSite=Lax comes in by allowing the cookie to be sent with these top-level navigations. Let's revisit the cat article example from above where another site is referencing your content. They make use of your photo of the cat directly and provide a link through to your original article.

<p>Look at this amazing cat!</p>
<img src="https://blog.example/blog/img/amazing-cat.png" />
<p>Read the <a href="https://blog.example/blog/cat.html">article</a>.</p>

And the cookie has been set as so:

Set-Cookie: promo_shown=1; SameSite=Lax

When the reader is on the other person's blog the cookie will not be sent when the browser requests amazing-cat.png. However when the reader follows the link through to cat.html on your blog, that request will include the cookie. This makes Lax a good choice for cookies affecting the display of the site with Strict being useful for cookies related to actions your user is taking.

Finally there is the option of not specifying the value which has previously been the way of implicitly stating that you want the cookie to be sent in all contexts. In the latest draft of RFC6265bis this is being made explicit by introducing a new value of SameSite=None. This means you can use None to clearly communicate that you intentionally want the cookie sent in a third-party context.

Three cookies labelled None, Lax, or Strict depending on their context
Explicitly mark the context of a cookie as None, Lax, or Strict.

Changes to the default behavior without SameSite #

While the SameSite attribute is widely supported, it has unfortunately not been widely adopted by developers. The open default of sending cookies everywhere means all use cases work but leaves the user vulnerable to CSRF and unintentional information leakage. To encourage developers to state their intent and provide users with a safer experience, the IETF proposal, Incrementally Better Cookies lays out two key changes:

  • Cookies without a SameSite attribute will be treated as SameSite=Lax.
  • Cookies with SameSite=None must also specify Secure, meaning they require a secure context.

Chrome implements this default behavior as of version 84. Firefox has them available to test as of Firefox 69 and will make them default behaviors in the future. To test these behaviors in Firefox, open about:config and set network.cookie.sameSite.laxByDefault. Edge also plans to change its default behaviors.

SameSite=Lax by default #

No attribute set

Set-Cookie: promo_shown=1

If you send a cookie without any SameSite attribute specified…

Default behavior applied

Set-Cookie: promo_shown=1; SameSite=Lax

The browser will treat that cookie as if SameSite=Lax was specified.

While this is intended to apply a more secure default, you should ideally set an explicit SameSite attribute rather than relying on the browser to apply that for you. This makes your intent for the cookie explicit and improves the chances of a consistent experience across browsers.

SameSite=None must be secure #

Rejected

Set-Cookie: widget_session=abc123; SameSite=None

Setting a cookie without Secure will be rejected.

Accepted

Set-Cookie: widget_session=abc123; SameSite=None; Secure

You must ensure that you pair SameSite=None with the Secure attribute.

You can test this behavior as of Chrome 76 by enabling about://flags/#cookies-without-same-site-must-be-secure and from Firefox 69 in about:config by setting network.cookie.sameSite.noneRequiresSecure.

You will want to apply this when setting new cookies and actively refresh existing cookies even if they are not approaching their expiry date.

Both of these changes are backwards-compatible with browsers that have correctly implemented the previous version of the SameSite attribute, or just do not support it at all. By applying these changes to your cookies, you are making their intended use explicit rather than relying on the default behavior of the browser. Likewise, any clients that do not recognize SameSite=None as of yet should ignore it and carry on as if the attribute was not set.

For further detail on exactly how to update your cookies to successfully handle these changes to SameSite=None and the difference in browser behavior, head to the follow up article, SameSite cookie recipes.

Kind thanks for contributions and feedback from Lily Chen, Malte Ubl, Mike West, Rob Dodson, Tom Steiner, and Vivek Sekhar

Cookie hero image by Pille-Riin Priske on Unsplash

Return to all articles