Under RFC 6265, when does a new 'Set-Cookie' replace an existing cookie versus create a second cookie with the same name, and what does the client send if two same-named cookies both match a request?
answer
- identity = (name, Domain, Path)
- match → overwrite in place, creation time retained
- mismatch → second cookie, same name
- Cookie header: longest path first, then oldest
- default path = request directory; default domain = host-only
basics
~20 sA cookie's identity is the triple name, Domain, Path. A Set-Cookie matching all three replaces the old value in place, keeping its creation time. Differ in any one and you get a second cookie; both are then sent in the Cookie header, longest path first, and the server cannot tell them apart.
solid answer
~60 sThe user agent keys its store on **(name, Domain, Path)**. A new `Set-Cookie` whose triple matches an existing entry **overwrites** it — the value and attributes are replaced, and RFC 6265 preserves the original **creation time** while updating last-access time (so ordering behaviour stays stable across updates). If any of the three differs, the browser stores a **second, independent cookie with the same name**.\n\nOn the next matching request both are serialised into the one `Cookie` header, ordered by **longer path first**, then by earlier creation time. The server sees `Cookie: sid=stale; sid=fresh` with no attributes and no way to know which came from where — most frameworks then hand you whichever they parsed first, so behaviour depends on the parser.\n\nThe fix is discipline at write time: one owner per cookie name, always the same `Domain` and `Path` (usually explicit `Path=/`), issued through a single helper. To recover from an existing duplicate, emit an expiring `Set-Cookie` for **every** scope variant, since you cannot read the scopes of what came in.
code
http · 1 lineHTTP/1.1 200 OK\nSet-Cookie: sid=OLD; Path=/app\n\nHTTP/1.1 200 OK\nSet-Cookie: sid=NEW; Path=/\n\nGET /app/dashboard HTTP/1.1\nHost: example.com\nCookie: sid=OLD; sid=NEWgo deeper
Know that the same name can exist twice if the domain or path differ, and that a matching name, domain and path overwrites.
State the identity triple precisely, explain the request-derived defaults for Path and Domain, and describe the Cookie header's longest-path-first ordering.
Diagnose the production failure — duplicate cookies causing intermittent auth bugs — and prescribe centralised issuance, explicit Path=/, and a multi-scope cleanup sweep.
Make cookie identity a platform invariant: one owning service per cookie name, explicit scope policy across subdomains, and contract tests asserting the emitted Domain and Path.
## The identity triple\n\nA browser does not key cookies by name alone. The storage key is:\n\n**(name, Domain, Path)**\n\nWhen a `Set-Cookie` arrives, the user agent computes the effective domain and path (using the defaults if the attributes are absent) and looks for an existing cookie with the same triple:\n\n- **Match** → update in place. The value and all attributes are replaced with the new ones, and the stored **creation-time is retained** from the original entry while the last-access time is refreshed. Retaining creation time is deliberate: it keeps the cookie's position in the `Cookie` header stable so that refreshing a value does not reshuffle ordering.\n- **No match** → insert a new cookie. You now have two entries sharing a name.\n\nAttributes that are *not* part of identity — `Secure`, `HttpOnly`, `SameSite`, `Expires`/`Max-Age` — are simply overwritten on a match. That is why a partial rewrite is dangerous: `Set-Cookie: sid=new` matching the same triple keeps the entry but strips `Secure` and `HttpOnly` from it. (There is one asymmetry: a non-secure origin is not allowed to overwrite a cookie that was set with `Secure`.)\n\n## How duplicates arise\n\nThe defaults are the trap, because both defaults are computed from the request, not from your intent.\n\n- **Default path** is the *directory* of the request URI. A `Set-Cookie` with no `Path` issued from `/api/v1/login` gets `Path=/api/v1`; the same code called from `/login` gets `Path=/`. Two endpoints, two cookies, same name.\n- **Default domain** is **host-only** — exactly the host that sent the response. Adding `Domain=example.com` produces a *different*, subdomain-spanning cookie. A cookie set by `app.example.com` with no `Domain` and one set by `example.com` with `Domain=example.com` coexist happily under the same name.\n- **Deployment drift**: an old release set `Path=/app`, the new one sets `Path=/`. Users who logged in before the deploy carry both forever, because your new code's delete only matches one of them.\n\n## What the server receives\n\n```\nCookie: sid=OLD-from-/app; sid=NEW-from-/\n```\n\nSerialisation order is specified: cookies with a **longer path** come first; ties broken by **earlier creation time**. But the server gets no attributes, so it cannot attribute a value to a scope. Frameworks differ in what they hand you — first wins, last wins, or a list — so the same duplicated jar produces different behaviour in different services behind the same gateway. Typical symptoms: intermittent logouts, a login that appears to succeed but leaves you anonymous, CSRF token mismatches, and "works in a fresh profile, fails for long-standing users" bug reports that no one can reproduce.\n\nBecause creation time breaks ties and the stale cookie is usually the older one at a longer path, the **stale** value very often sorts first — the worst possible outcome.\n\n## Diagnosis\n\nOn the request side you are blind, so look at the client: browser devtools' Application → Cookies panel lists each entry with its domain and path, which is the only convenient view of the triples. In logs, count the occurrences of a cookie name in the `Cookie` header — a name appearing twice is definitive proof of a duplicate and is worth an explicit metric on any auth service.\n\n## Fixing and preventing\n\n1. **One writer per name.** A single helper owns each cookie's name, `Domain`, `Path`, `Secure`, `HttpOnly` and `SameSite`; both the set and the clear paths call it. Never hand-build a `Set-Cookie` in a controller.\n2. **Always set `Path` explicitly**, normally `Path=/`. Never rely on the request-derived default, which silently varies by endpoint.\n3. **Be deliberate about `Domain`.** Omit it for host-only (the safer default), or set it once, consistently, everywhere. Mixing the two is the most common source of same-named duplicates.\n4. **Rewrite completely.** Every `Set-Cookie` restates the full attribute set, because a partial rewrite silently drops flags.\n5. **Clean up existing duplicates** by emitting expiring `Set-Cookie` headers for every scope you have ever used — the old `Path=/app` variant, the `Domain=example.com` variant, and the host-only one — since you cannot detect from the request which exist.\n6. **Detect regressions in tests**: assert the exact `Domain` and `Path` your login response emits, so a refactor that moves the endpoint cannot silently change the cookie's identity.\n\nThe short version an interviewer wants: identity is name plus domain plus path; matching triples overwrite in place and keep the creation time; mismatched triples duplicate; duplicates arrive together, longest path first, indistinguishable at the server; prevention is centralised, explicit scoping.
- You suspect a user has two cookies named sid. How do you confirm it and clean it up?Confirm it by counting occurrences of the name in the incoming Cookie header — two 'sid=' pairs prove duplicate scopes — or by inspecting the browser's cookie panel, which shows domain and path per entry. Clean up by sending an expiring Set-Cookie for every scope combination your application has ever used, since the request itself never reveals which scopes exist.
- Does changing Secure or SameSite on a cookie create a new cookie?No. Only name, Domain and Path form the identity, so a Set-Cookie with the same triple updates the existing entry and replaces its other attributes wholesale. That is precisely why an incomplete rewrite is dangerous: omitting Secure or HttpOnly does not preserve them, it strips them from the stored cookie.
Filing by name plus drawer plus folder. Refile into the same drawer and folder and you replace the sheet; use a different folder and you now have two sheets with the same title, and the clerk who fetches them hands you both with no note of which folder each came from.
saying these in an interview costs you the question
- Believing the cookie name alone identifies a cookie, so a new Set-Cookie always overwrites
- Assuming a cookie with no Domain is equivalent to one with Domain set to the same host
- Relying on the default Path instead of setting Path=/ explicitly
- Thinking the server can tell which of two same-named cookies came from which scope
- Expecting one deletion to clear duplicates that were created under different scopes