Even though I’ve been doing web things for a while now, I confess I had never dealt with browser cookies other than clicking those cookie notifications on every other website you visit these days.
I mean, I knew that it was a form of storage on the browser, but I’d always used
localStorage for that. Recently I was working on something that used browser cookies and I figured it was a good time to figure them out.
I love the name cookie, but I can’t help but wonder if there was a reason for it. Turns out I’m not the only person who had that question. And the inventor of browser cookies, Lou Montulli explained that he had heard the term ‘magic cookie‘ from an operating systems course in college that had a similar meaning to the way his proposed solution for a session identifier worked.
The original problem he was trying to solve was the implementation of an online shopping cart, which eventually led to the original specification for persistent client state, and has since evolved into the current RFC 6265. The first cookies were used to verify repeat visitors to the Netscape website.
A cookie is a small plain text file stored in the browser. There isn’t anything executable in there. It simply contains a small amount of data. Every browser stores them in a slightly different location (e.g. Where cookies are located in Windows 10, for all web browsers).
The data in the cookie is sent over by the server, stored on the user’s browsers, then used in subsequent requests as an identifier of sorts. Cookies are mainly used to remember state (if you are logged in, shopping cart items, user preferences etc.) as well as tracking.
Cookies are created when the server sends over one or more
Set-Cookie headers with its response, something along these lines:
It could be any name-value pair, but each cookie can contain only 1 name-value pair. If you need more than 1 cookie, then multiple
Set-Cookie headers are needed. An example of a server sending over cookie headers to the browser looks something like this:
HTTP/2.0 200 OK Content-Type: text/html Set-Cookie: viola=red_panda Set-Cookie: mathia=polar_bear
As a frontend developer, I must admit I don’t debug server-sent headers very often so this is not something I see on a regular basis. Once the cookie is set, all subsequent requests to the server from the browser will also have the cookies in its request header.
GET /demos/cookie/ HTTP/2 Host: huijing.github.io Cookie: viola=red_panda; mathia=polar_bear
document.cookie. Browser cookies also have a number of attributes in addition to the name-value pair mentioned earlier.
The cookie name can be any US-ASCII characters except control characters, spaces, tabs or separator characters. The cookie value can be optionally wrapped in double quotes and be any US-ASCII characters except control characters, double quotes, commas, semicolons, backslash and whitespace.
Adding special prefixes to the cookie name also forces certain requirements. If your cookie name starts with
__Secure-, it must be set with the
secure flag from a page served with
HTTPS. If your cookie name starts with
__ Host-, it must be set with the
secure flag from a page served with
HTTPS, it must not have a domain specified and its path must be
The rest of the attributes are optional but can impact cookie behaviour significantly depending on what values are set.
When a cookie passes its expiry date, it will no longer be sent with browser requests, and instead will be deleted. The date value is a HTTP timestamp.
Also related to a cookie’s expiry, but in seconds. After the specified amount of time, the cookie will expire, so setting it to 0 or a negative number means instant expiry.
Max-Age takes precedence over
Expires if both are set.
Specifies the host where the browser cookie gets sent to. Only a single domain is allowed. If not present, this defaults to the current document URL’s host. When specified, all sub-domains are included as well.
Cookie will only be sent if the path exists in the current URL
Cookie will only be sent when the request is made with HTTPS
document.cookie (to mitigate XSS attacks)
Specifies if a cookie is sent with cross-origin requests.
Strictmeans the cookie is only sent for requests originating from the same URL as the current one.
Laxmeans the cookie is not sent on cross-site requests, but will be sent if the user navigates to the origin site from an external site.
Nonemeans the cookie will be sent on both same-site and cross-site requests, but can only be used if the
Secureattribute is also set.
If you use Firefox, you may notice a console log message like this on some websites.
Back in August 2020, Mozilla made the decision to treat cookies as
SameSite=Lax by default, and require cookies with
SameSite=None to also set the
Secure attribute. The original behaviour for cookies was
SameSite=None but this leaves users susceptible to Cross-Site Request Forgery attacks.
Both Chrome and Firefox has rolled this out, but it seems like only Firefox displays the console log warning? If you can verify the console logging situation, please let me know.
Cookies without an
Max-Age attribute are treated as session cookies, which means they are removed once the browser is closed. Setting a value on either
Max-Age makes them permanent cookies, since they will exist until they hit their expiry date.
Again, I usually don’t do server-side stuff so I’ll only talk about messing around with cookies on the client-side. The
Document has a
To see all cookies associated with the document, use
document.cookie. You can type this in the browser’s console and see something like this:
To create a new cookie, you can do something like this:
document.cookie = "xiaohua=tortoise"
If you need more than one cookie, you’ll have to do this for every cookie you want to create.
Even if you refresh the page, the cookie should still be there. To get rid of the cookie, or reset it, you can set the
Expires value to the beginning of time itself,
Thu, 01 Jan 1970 00:00:00 GMT. I’m semi-kidding. Just in case you never heard of this interesting (and fairly important) piece of trivia, I shall quote MDN:
For example, if I wanted to get rid of the
taria cookie, I would do this:
document.cookie = "taria= ;expires=Thu, 01 Jan 1970 00:00:00 GMT"
It’s been a while since I last published anything. I suppose this is the longest hiatus I’ve had since I started this blog, but somehow being stuck in the same place doesn’t seem to motivate me to write words. But we’ll see.
Meanwhile, go eat some of your favourite cookies.
- Cookies, Chaos and the Browser: Meet Lou Montulli
- Using HTTP cookies
- Set-Cookie on MDN
- Document.cookie on MDN
Credits: OG:image from Red Panda Loves Cookies video on Oregon Zoo Youtube channel