SameSite cookies

  1. What are first-party and third-party cookies?
  2. Explicitly state cookie usage with the SameSite attribut
  3. Changes to the default behavior without SameSite
    1. Warning
  4. SameSite cookie recipes

Modern browsers (including Chrome, Firefox, and Edge) are changing their bahavior to enforce more privacy-preserving defaults.

Servers set cookies by sending the aptly-named Set-Cookie header in their response.

The header looks like this:

1
Set-Cookie: promo_shown=1; Max-Age=2600000; Secure

Servers set cookies using the Set-Cookie header.

When users on a secure connection and the cookie is less than a month old, then their browser will send this header in its request:

1
Cookie: promo_shown=1

Your browser sends cookies back in the Cookie header.

You can also access the cookies available to that site in JavaScript using document.cookie. Making an assignment to document.cookie will create or overwrite a cookie with that key.

1
2
> document.cookie = "promo_shown=1; Max-Age=2600000; Secure"
< "promo_shown=1; Max-Age=2600000; Secure"

Reading document.cookie will output all the cookies accessible in the current context, with each cookie separated by a semicolon:

1
2
> document.cookie;
< "promo_shown=1; color_theme=peachpuff; sidebar_loc=left"

JavaScript can access cookies using document.cookie.

What are first-party and third-party cookies?

Cookies that match the domain of the current site, i.e. what’s displayed in the browser’s address bar, are referred to as first-party cookies.

Similarly, cookies from domains other than the current site are referred to as third-party cookies.

This isn’t an absolute label but is relative to the user’s context; the same cookie can be either first-party or third-party depending on which site the user is on at the time.

Cookies may come from a variety of different domains on one page.

A cookie in a third-party context is sent when visiting different pages.

Cross-site request forgery (CSRF) attacks rely on the fact that cookie are attached to any requests to a given origin, no matter who initiates the request. For example, if you visit evil.example then it can trigger requests to your-blog.example, and your browser will happily attach the associated cookies. If your blog isn’t careful with how it validates those requests then evil.example could trigger actions like deleting posts or adding their own content.

The introduction of the SameSite attribute 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.

If the user is on www.web.dev and requests an image from static.web.dev then that is a same-site request.

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.

If the user is on your-project.github.io and requests an image from my-project.github.io that’s a cross-site request.

  • Strict: Cookies 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.
    This is good when you have cookies relating to functionality that will always be behind an initial navigation.
  • Lax: Allows the cookie to be sent with these top-level navigations.
    This is a good choice for cookies affecting the display of the site.
  • None: No restrictions will applied. The cookie will be sent in all requests - both cross-site and same-site.
    This means you can use None to clearly communicate that you intentionally want the cookie sent in a third-party context.
    If you provide a service that other sites consume such as widgets, embedded content, affiliate programes, advertising, or sign-in across multipile sites then you should use None to ensure your intent is clear.

Explicitly mark the context of a cookie as None, Lax, or Strict.

Changes to the default behavior without SameSite

  • 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.

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.

Warning

A number of older versions of browsers including Chrome, Safari, and UC browser are incompatible with the new None attribute and may ignore or restrict the cookie. This behavior is fixed in current versions, but you should check your traffic to determine what proportion of your users are affected. You can see the list of known incompatible clients on the Chromium site.

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.

Ref:
https://web.dev/samesite-cookies-explained/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite