Cookies: document.cookie

In this chapter, we will cover one of the ways of storing data in the browser: cookies.

Cookies are small data strings, stored directly in the browser. They are included in the HTTP protocol.

As a rule, the web-server sets cookies with the help of a response Set-Cookie HTTP header. After that, the browser adds them to each request to the same domain, using the Cookie HTTP header.

Among the most common cases is authentication:

  1. During the sign-in, the server applies the Set-Cookie HTTP header in the response for setting a cookie with a specific “session identifier”.
  2. The next time if the request is set to the same domain, the cookie is sent over the net by the browser, with the help of the Cookie HTTP header.
  3. In that way, the servers know who the request was made by.

Also, you can use the document.cookie property for accessing cookies from the browser.

Cookies can be quite tricky at times. Read on to learn more details about cookies.

One of the most common issues is how to know whether the browser stores cookies or not.

To check the browser for cookies, you can act like this:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // At w3docs.com, we use Google Analytics for statistics,
      // so there can be some cookies      
      alert(document.cookie); // cookie1=value1; cookie2=value2;...
    </script>
  </body>
</html>

The value of document.cookie involves name=value pairs that are delimited by ;. Each of them is a separate cookie. For finding a particular cookie the document.cookie can be split by ;, and then the right name will be found. Here you can use either a regular expression or array functions for doing that.

A writing operation to document.cookie updates merely the cookies that are mentioned inside it. It doesn’t touch other cookies.

Let’s see an example where the call sets a cookie with the name user and value Jack:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      document.cookie = "user=Jack"; // update just the cookie named 'user'
      alert(document.cookie); // show all the cookies
    </script>
  </body>
</html>

Multiple cookies will appear after running the code above. The reason is that document.cookie= operation doesn’t overwrite all the existing cookies. All that it does is mentioning the cookie user.

The name and the value can technically have any characters. To keep the valid formatting, you should escape them using a built-in encodeURIComponent function, like this:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // special characters (spaces), need encoding
      let name = "firstname lastname";
      let value = "Jack Down"      
      // encodes the cookie as firstname%20lastname=Jack%20Down
      document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);      
      alert(document.cookie); // ...; firstname%20lastname=Jack%20Down      
    </script>
  </body>
</html>

Cookies include multiple options. Many of them are essential and must be set.

They should be listed after key=value, delimited, as follows:

document.cookie = "user=Jack; path=/; expires=Mon, 11 Apr 2020 04:25:18 GMT"

Path

The path is the url path prefix (path=/mypath). The cookie is accessible under that path. It should be absolute. It is the current path, by default.

In case a cookie is set with path=/admin, it can be visible at pages /admin and /admin/something/admin/something but not /adminpage or /home.

Usually, the path is to the root path=/ for making the cookie accessible from all the pages.

Domain

It’s the domain where the cookie is accessible (domain=anysite.com). But, in practice, it is not possible to set any domain. There are certain limitations.

A cookie can be accessed only at the domain, which sets it.

Here is an example:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // at anysite.com
      document.cookie = "user=Jack"      
      // at forum.anysite.com
      alert(document.cookie); // no user      
    </script>
  </body>
</html>

So, there is no way of allowing a cookie to be accessible from another second-level domain. Hence, another.com can never receive a cookie set at site.com. But, in case of allowing subdomains, such asforum.anysite.com receive a cookie, it’s possible. Once setting a cookie at site.com, it is necessary to explicitly set domain option to the root domain such as domain=anysite.com, like this:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // at anysite.com
      // make the cookie accessible on any subdomain *.anysite.com:
      document.cookie = "user=Jack; domain=w3docs.com"      
      // later      
      // at forum.anysite.com
      alert(document.cookie); // has cookie user=Jack        
    </script>
  </body>
</html>

So, with the domain option, you can make a cookie acceptable at subdomains.

Expires, Max-age

If a cookie doesn’t have one of these options, it fades away when the browser is closed. Cookies like that are known as”session cookies”.

For allowing cookies to survive the browser close, you need to set either expires or max-age option, like this:

expires=Mon, 11 Apr 2020 04:25:18 GMT

In the example above, you can see the expiration date of the cookie. It should be exactly in the mentioned format, in the GMT timezone. You can also use date.toUTCString for getting it.

In the example below, a cookie expiring in 3 days is demonstrated:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // +3 days from now
      let date = new Date(Date.now() + 3);
      date = date.toUTCString();
      document.cookie = "user=Jack; expires=" + date;
      alert(document.cookie);
    </script>
  </body>
</html>

In case you set expires to a date in the past, the cookie will be deleted.

Themax-age=3600 is an alternative to expires. It indicates the cookie expiration in seconds from the current moment. When it’s negative or zero, the cookie is deleted, like here:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // cookie will disappear +2 hour from now
      document.cookie = "user=Jack; max-age=7200";
      alert(document.cookie);
      // delete cookie,let it expire right now
      document.cookie = "user=Jack; max-age=0";
      alert(document.cookie);          
    </script>
  </body>
</html>

Secure

With the secure option, if the cookie is set by https://anysite.com, it will not appear when the same site is accessed by HTTP, as https://anysite.com. Therefore, in case a cookie has sensitive content, then you shouldn’t send it over unencrypted HTTP. Here the secure option will help, as in the example below:

<!DOCTYPE HTML>
<HTML>
  <head>
  </head>
  <body>
    <script>
      // assuming you're on https:// now
      // set the cookie secure (only accessible if over HTTPS)
      document.cookie = "user=Jack; secure";
      alert(document.cookie );         
    </script>
  </body>
</html>

Samesite

The next security attribute is samesite. It is created for protection from so-called XSRF (cross-site request forgery) attacks. The XSRF attack is a type of malicious exploit of a website, in which unauthorized commands can be transmitted from a user the web app trusts.

Samesite is a perfect option for protecting from such attacks but it has drawbacks too. It is ignored by older browsers ( 2017 or so).

So, it is not recommended to solely rely on the samesite for protection. Old browsers will be vulnerable. Using it along with other measures, such as xsrf tokens will add an extra layer to your protection.

There is a small but convenient set of functions for working with cookies. It is handier than a manual modification of the document.cookie.

The shortest way to access cookies is by using regular expressions.

getCookie(name)

This function is used for returning the cookie with a particular name.

Here is an example of using the getCookie(name) function:

// returns the cookie with a specific name,
// or undefined if not found
function getCookie(name) {
  let m = document.cookie.match(new RegExp(
    "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
  ));
  return matches ? decodeURIComponent(m[1]) : undefined;
}

In the example above, a new RegExp is created dynamically to correspond ; name=<value.

Also, consider that a cookie value is encoded. Therefore, getCookie applies a built-in decodeURIComponent component for decoding it.

SetCookie(name, value, options)

This method sets the cookie name to a particular value with path=/ by default, as follows:

function setCookie(name, value, options = {}) {
  options = {
    path: '/',
    // add other default values if necessary
    ...options
  };
  if (options.expires instanceof Date) {
    options.expires = options.expires.toUTCString();
  }

  let updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);
  for (let optKey in options) {
    updatedCookie += "; " + optKey;
    let optValue = options[optKey];
    if (optValue !== true) {
      updatedCookie += "=" + optValue;
    }
  }
  document.cookie = updatedCookie;
}
// Example of use:
setCookie('user', 'Jack', {
  secure: true,
  'max-age': 7200
});

DeleteCookie(name)

For deleting a cookie, you can just call it with a negative expiration date, as demonstrated below:

function deleteCookie(name) {
  setCookie(name, "", {
    'max-age': -1
  })
}

While deleting or updating a cookie, you should consider that it is always necessary to use the same path and domain options as you set it with.

Summary

Cookies are an easy and versatile means to store data in the web browser. In other words, it gives “memory” to web browsers and servers.

A cookie is a piece of data that is stored on a computer to be accessed by the browser. Almost everyone enjoys the benefits of cookies both knowingly and unknowingly. For example, saving a Facebook password and not having to type it again every time logging in, is a sign of using cookies.

For accessing cookies, the document.cookie property is used.

Small and convenient methods, such as getCookie(name), setCookie(name, value, options), and deleteCookie(name) are used to make working with cookies more efficient.

The secure and samesite options are used for making it safer to work with cookies.




Do you find this helpful?

Related articles