First-party cookie recipes
Learn how to set first-party cookies to ensure security, cross-browser compatibility, and minimize chances of breakage once third-party cookies are phased out.
Cookies can be first-party or third-party relative to the user's context; depending on which site the user is on at the time. If the cookie's registrable domain and scheme match the current top-level page, that is, what's displayed in the browser's address bar, the cookie is considered to be from the same site as the page and it's generally referred to as a first-party cookie.
Cookies from domains other than the current site are generally referred to as third-party cookies.
The good first-party cookie recipe #
If the cookie you're setting is not used across sites, for example, it's used to manage sessions on your site and it's never used in a cross-site iframe, that cookie is always used in a first-party context.
The following configuration is best practice, ensuring security and cross-browser compatibility for most first-party cookies. It will provide you with a safe foundation, which you can adjust to open up permissions only when necessary. This article also covers recipe variations for some specific use-cases.
The recipe #
__Host is an optional prefix that makes some attributes mandatory and forbids others:
Securemust be present
Domainmust be omitted
__Host added, you can rely on the browser to check if attributes above are set in line with
__Host rules and reject the cookie if not.
Secure protects cookies from being stolen on insecure networks because it only allows sending cookies over HTTPS connections. If you haven't fully migrated your site to HTTPS, make that a priority.
Domain attribute specifies which hosts can receive a cookie. Omitting it restricts the cookie to the current document host, excluding subdomains: the cookie for
example.com will be sent on every request to
example.com but not on requests to
images.example.com. If you have different apps running on different subdomains, this reduces the risk of one compromised domain allowing a door into the others.
Path indicates the path that must exist in the requested URL for the browser to send the
Cookie header. Setting
Path=/ means that the cookie is sent to all URL paths on that domain. The combination of no
Path=/ makes the cookie bound to the origin as closely as possible, so it behaves similarly to other client-side storage such as
LocalStorage—there's no confusion that
example.com/a might receive different values to
Max-Age limits the life of a cookie as browser sessions can last a pretty long time and you don't want stale cookies hanging around forever. It's good for short-term cookies, such as user sessions or even shorter ones such as tokens for form submission.
Max-Age is defined in seconds and in the example above it's set to 7776000 seconds which is 90 days. This is a reasonable default, which you can change depending on your use case.
SameSite=Lax restricts the cookie to only be sent on same-site requests. That is, where the request matches the current browsing context–the top level site the user is currently visiting which is displayed in their location bar.
SameSite=Lax is the default in modern browsers but it's good practice to specify it for compatibility across browsers which may have different defaults. By explicitly marking the cookie as same-site only, you are restricting it to your first-party contexts, and you should not have to make changes to that cookie when third-party cookies go away.
To learn more about different cookie attributes, check out
Set-Cookie documentation on MDN.
First-party cookie recipe for sites with subdomains #
If you have a site with subdomains and want to have one session across all of them, the
Host prefix can be too restrictive. For example
news.site could have subdomains for topics, such as
sport.news.site and you'd want one user session on all of them. In that case, use the
__Secure prefix instead of
__Host and specify
The recipe #
__Secure is an optional prefix which asserts fewer requirements than
__Host: it only requires that the cookie be set with the
Restricting first-party cookie access on requests initiated from third-party websites #
SameSite=Lax cookies are not sent on cross-site subrequests (for example, when loading embedded images or iframes on a third-party site), they are sent when a user is navigating to the origin site (for example, when following a link from a different site).
You can further restrict cookies access and disallow sending them along with requests initiated from third-party websites with
SameSite=Strict. This is useful when you have cookies relating to functionality that will always be behind an initial navigation, such as changing a password or making a purchase.
The recipe #