Working With Cookies in JavaScript - The Ultimate Guide

Cookies, also known as HTTP cookies, are small bits of information stored on the user's computer by the user's web browser. Cookies are most commonly used to track persistent user data and website activity and are grouped by a domain name.

Cookies can only contain string values, meaning arrays, objects, and other complex data types cannot be stored within a cookie unless those objects are converted to string format. Luckily, you can use the JavaScript JSON.stringify() method to stringify these types of objects as needed.

Why Use Cookies?

Web browsers communicate with servers using HTTP, a stateless protocol where each page request is handled independently, dismissing any data once it has been submitted to the web browser.

In many situations, websites or applications may require user authentication to enter some type of dashboard or portal, which is not retained in memory on the server. Enter cookies, the client-side storage solution for storing information within your web browser that can be accessed both client-side and server-side, and is retained either indefinitely or until the cookie's expiration date has been met.

The Anatomy of a Browser Cookie

Browser cookies require a few key/value pairs including a name attribute, which is the name of the cookie, and a value attribute containing the cookie's value. You can also set a few optional attributes like domain, path, and expiry date.

The domain attribute signifies the domain for which the cookie is valid, and can be used with every request within its domain or subdomains. The path attribute signifies the URL or path for which the cookie is valid within the specified domain. The default value is / meaning the cookie would be valid within the root directory and all subdirectories of the specified domain.

Here is an example of a browser cookie named id with a value of 12345:

  • Name: id
  • Value: 12345
  • Domain: .example.com
  • Path: /
  • Expires: 2023-03-12T07:13:47.000Z
  • Max-Age: 600
Cookies can store up to 4,096 bytes of data, which includes all attributes and values combined within the cookie like name, value, domain, path, expiry, etc. There is also a limit to the number of cookies you can store per domain and is dependent on which web browser you're using.

How to Create a Browser Cookie

In JavaScript, the document.cookie property allows you to manage cookies, although it can become slightly complicated as the number of cookie values grows.

Here's an example of how you can output the current domain cookies in the developer console:

console.log(document.cookie);
// _ga=GA1.2.1512728751.1587476318; _gid=GA1.

Here, the Google Analytics cookie names and values are being output to the developer console.

If we wanted to create a new cookie, we could do so like this:

function createCookie (name, value) {
document.cookie = name + "=" + value + ";";
}

createCookie("foo", "bar");

console.log(document.cookie);
// _ga=GA1.2.1512728751.1587476318; _gid=GA1.; foo=bar;

A new cookie with name foo and value bar has been appended to the document.cookie property and now outputs at the end of the string.

Cookie Max-Age vs Expires

By default, cookies will be removed from your web browser once it has been closed. To prevent this, you can set a cookie to expire within a certain timeframe. There are two ways to do this:

  • Expires: A fixed expiration date. This date is in HTTP date format: [day-of-week], [day]-[month]-[year] [hour]:[minute]:[second] GMT.
var expire_date = new Date(2023, 3, 12);
document.cookie = "foo=bar; expires = " + expire_date.toUTCString() + ";";
  • Max-Age: The amount of time, in seconds, until the cookie expires. This is not supported by every browser, but is effective and easier to initiate, especially for testing purposes.
var expire_seconds = 24 * 60 * 60;
document.cookie = foo=bar; max-age = " + expire_seconds + ";";

Updating Browser Cookies

You can take a very similar approach with updating existing cookie values. Take this example:

function updateCookie (name, value) {
document.cookie = name + "=" + value + ";";
}

updateCookie("foo", "bar2");

console.log(document.cookie);
// _ga=GA1.2.1512728751.1587476318; _gid=GA1.; foo=bar2;

The document.cookie property will now take the existing cookie named foo and update its value from bar to bar2.

Accessing Browser Cookies Individually

Since document.cookie is saved in string format with key/value pairs separated by semi-colons, it makes retrieving the data a bit daunting. Let's create a new function call that will return the value of a cookie by its name:

function getCookie(cookie_name) {
var cookies = document.cookie.split(";");

for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].split("=");
var name = cookie[0].trim();
var value = cookie[1];

if (name == cookie_name) {
return value;
break;
}
}

return null;
}

console.log(getCookie("foo"));
// bar2

The above example parses the document.cookie data and searches for the value of foo. If found, the value is returned and the loop is exited. If not found, null is returned.

The trim() function is used for the cookie name to trim any whitespace around the name in the string. This is due to the spaces separating each cookie item. Without it, the cookie name/value pair could get passed over and not found correctly.

Deleting Browser Cookies

To delete a browser cookie, we'll use a similar approach as we did when creating and updating cookies. The only difference is we'll be setting a Max-Age value of -1 which tells the web browser that the cookie is now expired and can be removed:

function deleteCookie (name) {
document.cookie = name + "=; Max-Age=-1;";
}

deleteCookie("foo");

console.log(document.cookie);
// _ga=GA1.2.1512728751.1587476318; _gid=GA1.;

Cookie Security

By default, cookies ignore the protocols, meaning they can be accessed and managed whether you're using the HTTP or HTTPS protocols because they're domain specific, not protocol specific.

This isn't ideal in all cases.  If you have a cookie that contains sensitive information that you don't want accessed over an insecure protocol with no encryption, then there's a solution for that.

The secure flag ensures that the specified cookie data should be transferred only over the secure protocol, HTTPS:

document.cookie = "foo=bar; secure";

The httpOnly Flag

This has almost nothing to do with JavaScript, but I felt that it was important to include it anyway to help you understand the difference between creating cookies client-side and server-side.

By setting the httpOnly flag server-side, you're forbidding the cookie to be accessed client-side with JavaScript.  This is used as a precaution measure to further protect against sensitive information and XSS (cross-site scripting) attacks.

The samesite Flag

One additional security measure you can add to your cookies is a samesite flag, which allows the cookie to only become accessible within its assigned domain.

samesite=strict, or just samesite, is not accessible from the outside of the same site, just like its name suggests.  If a user were to access your site from an email or a form submission from another website, the cookies saved for your website  would not be accessible in any way.

There is a small workaround by using samesite=lax that works just like strict mode but with two exceptions:

  • 1. The HTTP method must be safe.  You can use the GET method, but not the POST method.  Here's a full list of HTTP methods.
  • 2. A top-level navigation action is performed, meaning the user changes the URL in the browser's address bar.  If navigation were to be performed in an iframe element, then it wouldn't work as this is not considered top-level navigation.

Conclusion

Although the process of creating and managing web browser cookies in JavaScript may be difficult at first, you'll get the hang of it after playing around with the features and performing some some real-world examples.