Why is my cookie not being set? (SameSite, Secure, Domain, Path)

When a cookie "isn't being set", one of two things is happening: the browser rejected the Set-Cookie header, or it stored the cookie and is choosing not to send it. The network panel tells you which, and the fix is different for each.

First: rejected, or just not sent?

In DevTools open Network, pick the response that sets the cookie and open its Cookies tab (Firefox: Cookies in the request details). A cookie listed under the response with a warning was rejected. Then check Application → Cookies (Firefox: Storage): if the cookie is there but missing from a later request's Cookie header, it was stored and not sent.

Rejected: the browser refused the Set-Cookie

HeaderWhy it's droppedFix
SameSite=None without SecureBrowsers require None cookies to be HTTPS-only.Add Secure, serve over HTTPS.
Secure on an http:// pageInsecure pages can't set or overwrite Secure cookies (localhost excepted).Use HTTPS, or drop Secure for local http testing only.
Domain=other.comA host can only set cookies for itself or a parent domain.Set it from the right host, or leave Domain out.
Domain=co.uk / github.ioPublic suffixes are shared by unrelated sites.Use your own registrable domain.
__Host-sid with a Domain or Path=/xThe prefix demands Secure, Path=/ and no Domain.Match the prefix rules or rename.
Over 4,096 bytesSize limit for name plus value.Store an ID, keep data server-side.
Expires in the past / Max-Age=0Not rejected exactly: it deletes the cookie.Check your server clock and units (seconds, not ms).

Stored but not sent

fetch and XHR never send cookies cross-origin unless you ask

// front end on https://app.example.com calling https://api.example.com
fetch('https://api.example.com/me', { credentials: 'include' })

// the API must answer with a specific origin, not *
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

Without credentials: 'include' (axios: withCredentials: true) the browser ignores Set-Cookie on the response and sends no cookies. The CORS side is in CORS with credentials.

A cookie that works everywhere on one site

Set-Cookie: __Host-sid=4f9a1c2e7b; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=1209600

Locked to this host over HTTPS, unreadable by scripts, sent on normal navigation, and gone after 14 days. Test variants in the Set-Cookie explainer, which also simulates whether each cookie would be sent for a link, a form POST or a background fetch.

Related

Want the bigger picture of what cookies are and how trackers use them? Wirebook's What is a cookie on a website? lesson shows it with a pretend café. Choosing where to keep a login token: localStorage vs cookies. Decoding a JWT you found in a cookie: decoding JWTs safely.

Server answering 431 or “Request Header Or Cookie Too Large”? See HTTP 431 explained. Forms failing with a CSRF error? See CSRF token missing or incorrect.

Checking cookies from a script or a CI job? The free Anvil Set-Cookie checker API runs these same rules and returns each reason as JSON.

Questions

Why does Chrome say this Set-Cookie was blocked because it had the SameSite=None attribute but did not have the Secure attribute?

Browsers only accept SameSite=None on Secure cookies. Add Secure and serve the response over HTTPS.

Why is my cookie only available on some pages?

It was probably set without Path, so it defaults to the folder of the URL that set it, such as /api. Add Path=/.

Why doesn't my API's cookie show up after fetch?

Cross-origin fetch ignores cookies unless you pass credentials: 'include' and the server replies with Access-Control-Allow-Credentials: true and a specific Access-Control-Allow-Origin.

Can localhost set a Secure cookie?

Yes. Browsers treat http://localhost as a secure context, so Secure cookies work there during development.

Why does my cookie vanish when I close the browser?

It has no Expires or Max-Age, so it is a session cookie. Add Max-Age (in seconds) to keep it.

Published .

Try it

Related guides

Newest guides