Guide
How the Set-Cookie and Cookie Headers Work
A plain walkthrough of how a server sets a cookie with Set-Cookie and how the browser sends it back with the Cookie header on later requests.
Key takeaways
- A server creates a cookie with a Set-Cookie response header and the browser returns it in a Cookie request header.
- Set-Cookie carries a name, a value and attributes; Cookie carries only names and values, never attributes.
- RFC 6265 says browsers should support at least 4096 bytes per cookie, 50 cookies per domain and 3000 in total, so keep cookies small.
- To update or delete a cookie, repeat the same name, domain and path; if one differs, the browser keeps the original.
- The browser has the final say and may reject or delete a cookie, so treat every cookie as something that can vanish.
Why does HTTP need cookies?
HTTP is stateless. Each request arrives at the server as an independent message, and nothing in the protocol itself says that two requests came from the same person or the same browser tab. That is fine for reading a static page, but it breaks down the moment you want a login, a shopping basket, a language preference or a saved layout. Cookies are the standard way to add a small amount of memory on top of a stateless protocol.
The idea is simple. The server hands the browser a small named value. The browser stores it and, on later requests that match certain rules, attaches it automatically. The server reads the value and recognises the returning client. Everything else in cookie handling, including every attribute and every security rule, is about controlling when that automatic attachment happens and who can see or change the value.
Which two headers are involved?
There are exactly two headers at the centre of the mechanism. The response header is called Set-Cookie and travels from server to browser. The request header is called Cookie and travels from browser to server. They are not symmetrical, and mixing them up is a common source of confusion for people who are new to the topic.
- Set-Cookie appears in a response and carries one cookie, plus any attributes that describe how the browser should treat it.
- Cookie appears in a request and carries only name and value pairs, joined together on a single line. It never carries attributes.
- If a server wants to set three cookies, it sends three separate Set-Cookie headers. The browser, when it replies, folds the matching ones into one Cookie header.
Set-Cookie and Cookie compared
| Header | Direction | Carries | Attributes |
|---|---|---|---|
| Set-Cookie | Server to browser, in a response | One cookie: name and value | Yes, after the first semicolon |
| Cookie | Browser to server, in a request | All matching cookies as name=value pairs on one line | Never |
A first example
Suppose a visitor logs in. The response might include a header that looks like this: Set-Cookie: sid=abc123; Path=/; Secure; HttpOnly; SameSite=Lax. The first part, sid=abc123, is the cookie itself: a name, an equals sign and a value. Everything after the first semicolon is an attribute, separated by a semicolon and a space.
When the same browser makes its next request to a matching address, it adds a line such as Cookie: sid=abc123. Notice that Path, Secure, HttpOnly and SameSite are gone. The browser used them to decide whether to send the cookie, and then it dropped them. The server only ever sees the name and value, which is why a server cannot tell from a request alone whether a cookie was marked HttpOnly or what its expiry was.
Name, value and what is allowed in them
A cookie name is a token, so it should avoid spaces, semicolons, commas and control characters. A value is usually restricted to a safe set of printable characters, and many applications encode anything unusual before storing it, using base64 or percent-encoding. Browsers apply limits on size as well. A common guideline is that a single cookie of around four kilobytes, counting name and attributes, is the practical ceiling, and browsers also limit how many cookies each site may store. Exact numbers vary between browsers, so treat any figure as approximate and test in the browsers you support. RFC 6265 says general-use user agents should provide at least 4096 bytes per cookie (name, value and attributes together), at least 50 cookies per domain and at least 3000 cookies in total, and that servers should use as few and as small cookies as possible.
Because every matching cookie is sent with every matching request, large cookies have a real cost. A page that loads fifty images from the same host sends the cookie header fifty times. Keeping cookies small, and keeping rarely needed data on the server, is a sensible habit.
What is the life cycle of a cookie?
A cookie goes through a predictable life. First the server creates it with a Set-Cookie header. The browser validates it, checks that the attributes make sense for the origin, and stores it in its cookie jar, which is a per-profile store keyed by name, domain and path. On later requests, the browser looks through the jar for cookies that match the request address, drops any that have expired, applies the security rules, and sends what remains.
To update a cookie, the server sends another Set-Cookie with the same name, domain and path. The new value replaces the old one. To remove a cookie, the server sends the same name, domain and path again with an expiry in the past or a maximum age of zero. If any of those three identifying parts differ, the browser treats it as a different cookie, and the original stays in place. This is one of the most frequent reasons that a logout appears to succeed while the user stays logged in.
What is the difference between session and persistent cookies?
If a Set-Cookie header has no Expires and no Max-Age attribute, the browser treats the cookie as a session cookie and removes it when the browsing session ends. What counts as the end of a session is decided by the browser, and some browsers restore sessions on restart, so a session cookie can last longer than you expect. If an expiry or maximum age is present, the cookie is persistent and survives restarts until that time arrives or until the user clears it.
What the browser decides on its own
The browser, not the server, has the final say. It may reject a cookie that is too large, one whose domain does not match the response origin, one marked Secure but received over plain HTTP in current browsers, or one that violates a prefix rule. It may also delete cookies when storage is full, or when the user clears data, or when privacy settings block them. A well-built application treats a cookie as a hint that may vanish at any time and always handles the missing case gracefully.
Reading cookies from JavaScript
Scripts can read and write cookies through document.cookie, but only those not marked HttpOnly. The property returns a single string of name and value pairs, and assigning to it sets one cookie at a time, with attributes written in the same format as Set-Cookie. This is convenient for small client-side preferences, but it is also the reason sensitive cookies such as session identifiers should be marked HttpOnly, so that script injected by an attacker cannot read them.
Quick checklist for beginners
- Send Set-Cookie from the server in a response; expect Cookie in later requests.
- Use one Set-Cookie header per cookie, never a comma-joined list.
- Keep values small and treat them as untrusted input when they come back.
- To delete a cookie, match its name, domain and path exactly.
- Do not store secrets or personal details directly in a cookie value.
With this foundation, the rest of the cookie topic becomes a matter of learning the attributes one at a time and understanding how each one narrows or widens the set of requests that carry the cookie.
Sources and further reading
- RFC 6265: HTTP State Management Mechanism: the specification of Set-Cookie and Cookie, including attribute rules, Max-Age precedence over Expires and the minimum limits on cookie size and count.
- MDN: Using HTTP cookies: session and permanent cookies, deleting a cookie, regenerating session cookies at login, and why cookies suit storage poorly compared with Web Storage.
- MDN: Set-Cookie header: each attribute (Domain, Path, Expires, Max-Age, Secure, HttpOnly, SameSite, Partitioned) and the cookie prefix rules.
Frequently asked questions
Can a request carry cookie attributes such as HttpOnly?
No. The Cookie request header contains only names and values. Attributes exist only in the Set-Cookie response header and are used by the browser to decide when to send the cookie.
How do I send several cookies in one response?
Use one Set-Cookie header for each cookie. Most server frameworks let you call their cookie function several times, and they emit separate headers for you.
Why does my cookie not get deleted when I clear it?
The browser matches cookies by name, domain and path. If your deletion header uses a different domain or path than the original, the browser treats it as a different cookie and leaves the first one alone.
Is there a size limit for cookies?
Yes. RFC 6265 says browsers should support at least 4096 bytes per cookie (name, value and attributes together), at least 50 cookies per domain and at least 3000 in total. Real limits differ between browsers, so keep cookies small and test the browsers you support.