Setting first-party cookies for security and longevity
First-party cookies are set by the site the user is currently visiting—the registrable domain and scheme match what's shown in the browser's address bar. These cookies manage sessions, preferences, and other state that belongs to your own site. Because third-party cookies are being phased out, it's worth ensuring your first-party cookies are configured correctly now, rather than patching them later.
By default, cookies can be shared across sites, read by JavaScript, and transmitted over plain HTTP. That's a broader exposure than most first-party use cases need. While work continues on improving defaults through Privacy Sandbox and proposals like origin-bound cookies, you can tighten things up today with explicit cookie attributes.
The baseline recipe for most first-party cookies
For a cookie that never leaves your site—say, a session cookie that isn't used in cross-site iframes—this configuration provides a secure, cross-browser-compatible starting point:
Set-Cookie:
__Host-cookie-name=cookie-value;
Secure;
Path=/;
HttpOnly;
Max-Age=7776000;
SameSite=Lax;
Here's what each attribute is doing:
__Host-prefix: This optional prefix enforces strict rules at the browser level. When present, the cookie must includeSecure, must omitDomain, and must setPath=/. If any requirement is violated, the browser rejects the cookie entirely.Secure: Restricts the cookie to HTTPS connections, preventing interception on insecure networks. If your site isn't fully on HTTPS yet, that migration should be your first priority.- No
Domainattribute: Limits the cookie to the exact host that set it, excluding all subdomains. A cookie set forexample.comwon't be sent toimages.example.com, reducing the blast radius if one subdomain is compromised. Path=/: Sends the cookie to all URL paths on the host. Combined with the omittedDomain, this binds the cookie as closely as possible to its origin, much likeLocalStorage—there's no risk of different values being served to different paths.HttpOnly: Blocks JavaScript access viadocument.cookie, defending against malicious third-party scripts. The cookie is only sent in request headers.Max-Age=7776000: Sets a 90-day lifetime, a reasonable default that prevents stale cookies from lingering. Adjust the value to your use case; for short-lived tokens like form-submission protection, you'd want far less.SameSite=Lax: Ensures the cookie is only sent on same-site requests—those matching the top-level site in the address bar. Modern browsers default toLax, but declaring it explicitly guarantees consistent behavior across browsers with different defaults.
Sharing sessions across subdomains
The __Host- prefix becomes too restrictive when you need one session across multiple subdomains. For instance, if news.site has topic subdomains like finance.news.site and sport.news.site, and you want a shared user session, drop the __Host- prefix in favor of __Secure- while specifying a Domain:
Set-Cookie:
__Secure-cookie-name=cookie-value;
Secure;
Domain=news.site;
Path=/;
HttpOnly;
Max-Age=7776000;
SameSite=Lax;
The __Secure- prefix only mandates that the cookie be set with Secure—it doesn't impose the other __Host- constraints. That gives you the flexibility to include a Domain attribute covering all relevant subdomains.
Blocking cookie transmission on third-party-initiated requests
SameSite=Lax prevents cookies from being sent on cross-site subrequests, such as embedded images or iframes from other sites. However, it still allows cookies when the user navigates directly to your origin—following a link from elsewhere, for example.
For operations that should always require an initial navigation—like changing a password or completing a purchase—use SameSite=Strict. This stops the browser from sending the cookie alongside any request initiated from a third-party website:
Set-Cookie:
__Host-cookie-name=cookie-value;
Secure;
Path=/;
HttpOnly;
Max-Age=7776000;
SameSite=Strict;
The trade-off is clear: navigation to your site from an external page won't carry the cookie until the user interacts again, so reserve Strict for functionality that genuinely needs it.



