# Cookies, document.cookie Cookies are small strings of data that are stored directly in the browser. They are not a part of Javascript, but rather a part of HTTP protocol, defined by [RFC 6265](https://tools.ietf.org/html/rfc6265) specification. Most of the time, cookies are set by a web server. One of the most widespread use of cookies is authentication: 1. Upon sign in, the server uses `Set-Cookie` HTTP-header in a response to set a cookie with "session identifier". 2. The browser stores the cookie. 3. Next time when the request is set to the same domain, the browser sends the over the net using `Cookie` HTTP-header. 4. So the server knows who made the request. The browser provides a special accessor `document.cookie` for cookies. There are many tricky things about cookies and their options. In this chapter we'll cover them in detail. ## Reading from document.cookie ```online Do you have any cookies on this site? Let's see: ``` ```offline Assuming you're on a website, it's possible to see the cookies, like this: ``` ```js run // At javascript.info, we use Google Analytics for statistics, // so there should be some cookies alert( document.cookie ); // cookie1=value1; cookie2=value2;... ``` The string consist of `name=value` pairs, delimited by `; `. Each one is a separate cookie. To find a particular cookie, we can split `document.cookie` by `; `, and then find the right name. We can use either a regular expression or array functions to do that. To make things simple, at the end of the chapter you'll find a few functions to manipulate cookies. ## Writing to document.cookie We can write to `document.cookie`. But it's not a data property, it's an accessor. **A write operation to `document.cookie` passes through the browser that updates cookies mentioned in it, but doesn't touch other cookies.** For instance, this call sets a cookie with the name `user` and value `John`: ```js run document.cookie = "user=John"; // update only cookie named 'user' alert(document.cookie); // show all cookies ``` If you run it, then probably you'll see multiple cookies. That's because `document.cookie=` operation does not overwrite all cookies, but only `user`. Technically, name and value can have any characters, but to keep the formatting valid they should be escaped using a built-in `encodeURIComponent` function: ```js run // special values, need encoding let name = "<>"; let value = "=" // encodes the cookie as %3C%3E=%3D document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); alert(document.cookie); // ...; %3C%3E=%3D ``` ```warn header="Limitations" There are few limitations: - The `name=value` pair, after `encodeURIComponent`, should not exceed 4kb. So we can't store anything huge in a cookie. - The total number of cookies per domain is limited to 20+, depending on a browser. ``` Cookies have several options, many of them are important and should be set. The options are listed after `key=value`, delimited by `;`, like this: ```js run document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT" ``` ## path - **`path=/mypath`** The url path prefix, where the cookie is accessible. Must be absolute. By default, it's the current path. If a cookie is set with `path=/mypath`, it's visible at `/mypath` and `/mypath/*`, but not at `/page` or `/mypathpage`. Usually, we set `path=/` to make the cookie accessible from all website pages. ## domain - **`domain=site.com`** Domain where the cookie is accessible. By default, a cookie is accessible only at the domain that set it. So, if the cookie was set by `site.com`, we won't get it `other.com`. ...But what's more tricky, we also won't get the cookie at a subdomain `forum.site.com`: ```js // at site.com document.cookie = "user=John" // at forum.site.com alert(document.cookie); // no user ``` **There's no way to let a cookie be accessible from another 2nd-level domain, so `other.com` will never receive a cookie set at `site.com`.** It's a safety restriction, to allow us to store sensitive data in cookies. ...But if we'd like to grant access to subdomains like `forum.site.com`, that's possible. We should explicitly set `domain` option to the root domain: `domain=site.com`: ```js // at site.com, make the cookie accessible on any subdomain: document.cookie = "user=John; domain=site.com" // at forum.site.com alert(document.cookie); // with user ``` For historical reasons, `domain=.site.com` (a dot at the start) also works this way, it might better to add the dot to support very old browsers. ## expires, max-age By default, if a cookie doesn't have one of these options, it disappears when the browser is closed. Such cookies are called "session cookies" To let cookies survive browser close, we can set either `expires` or `max-age` option. - **`expires=Tue, 19 Jan 2038 03:14:07 GMT`** Cookie expiration date, when the browser will delete it automatically. The date must be exactly in this format, in GMT timezone. We can use `date.toUTCString` to get it. For instance, we can set the cookie to expire in 1 day: ```js // +1 day from now let date = new Date(Date.now() + 86400e3); date = date.toUTCString(); document.cookie = "user=John; expires=" + date; ``` If we set `expires` to the past, the cookie will be deleted. - **`max-age=3600`** An alternative to `expires`, specifies the cookie expiration in seconds. Can be either a number of seconds from the current moment, or zero/negative for immediate expiration (to remove the cookie): ```js // cookie will die +1 hour from now document.cookie = "user=John; max-age=3600"; // delete cookie (let it expire right now) document.cookie = "user=John; max-age=0"; ``` ## secure - **`secure`** The cookie should be transferred only over HTTPS. **By default if we set a cookie at `http://site.com`, then it also appears at `https://site.com` and vise versa.** That is, cookies only check the domain, they do not distinguish between the protocols. With this option, if a cookie is set by `https://site.com`, then it doesn't appear when the same site is accessed by HTTP, as `http://site.com`. So if a cookie has sensitive content that should never be sent over unencrypted HTTP, then the flag can prevent this. ```js // set the cookie secure (only accessible if over HTTPS) document.cookie = "user=John; secure"; ``` ## samesite That's another security option, to protect from so-called XSRF (cross-site request forgery) attacks. To understand when it's useful, let's introduce the following attack scenario. ### XSRF attack Imagine, you are logged into the site `bank.com`. That is: you have an authentication cookie from that site. Your browser sends it to `bank.com` on every request, so that it recognizes you and performs all sensitive financial operations. Now, while browsing the web in another window, you occasionally come to another site `evil.com`, that has a `