HTTP cookies are a fundamental aspect of the Web that enable sessions and help recognize users during their browsing experience.

Introduction

Cookies allow the exchange of information between the server and the browser, making it possible to customize user sessions and enable servers to identify users across requests.

HTTP is a stateless protocol, meaning that all requests to a server are treated the same, and the server cannot distinguish between a new request and a subsequent request from a client. Cookies serve as a solution to this problem.

In the past, cookies were used to store various types of data because there were no better alternatives available. However, with the advent of the Web Storage API (localStorage and sessionStorage) and IndexedDB, there are now more efficient options.

Cookies have a limited data capacity, and they are sent back and forth for each HTTP request, including requests for assets like images or CSS/JavaScript files.

The first version of cookies was introduced in 1994, and over time, they have been standardized in multiple RFC revisions. The latest specification for cookies is defined in RFC 6265, dated 2011.

Restrictions of Cookies

Here are some limitations of cookies:

  • Cookies can only store up to 4KB of data.
  • Cookies are private to the domain, which means a site can only read the cookies it has set and cannot access cookies from other domains.
  • Each domain can have a maximum limit of cookies (usually around 20, but this can vary across browsers).
  • The total number of cookies is also limited (specific limit is set by each browser implementation), and if this number is exceeded, new cookies will replace the older ones.

Cookies can be set and read both server-side and client-side. On the client-side, cookies are exposed through the document object as document.cookie.

Setting Cookies

To set a cookie, you can use the document.cookie property. For example:

document.cookie = 'name=Flavio';

This will add a new cookie to the existing ones without overwriting them. The value of the cookie should be URL-encoded using encodeURIComponent() to ensure it doesn’t contain any invalid characters.

Setting Expiration Date for Cookies

By default, cookies expire when the browser is closed. However, you can set an expiration date to persist the cookies beyond the browser session. The expiration date should be expressed in UTC format. Here’s an example:

document.cookie = 'name=Flavio; expires=Mon, 26 Mar 2018 17:04:05 UTC';

Alternatively, you can use the max-age parameter to specify the expiration in the number of seconds:

document.cookie = 'name=Flavio; max-age=3600'; // Expires in 60 minutes
document.cookie = 'name=Flavio; max-age=31536000'; // Expires in 1 year

Setting Path for Cookies

The path parameter specifies the document location for the cookie. It assigns the cookie to a specific path and sends it to the server only if the path matches the current document location or a parent location.

For example:

document.cookie = 'name=Flavio; path=/dashboard';

This cookie will be sent for URLs that match /dashboard, /dashboard/today, and other sub-URLs under /dashboard/, but not for URLs like /posts.

If you don’t set a path, the cookie defaults to the current document location. To apply a global cookie from an inner page, you need to specify path=/.

Setting Domain for Cookies

You can use the domain parameter to specify a subdomain for your cookie. For example:

document.cookie = 'name=Flavio; domain=mysite.com';

If not set, the domain defaults to the host portion, including the subdomain if applicable. Domain cookies are also included in subdomains.

Secure

Adding the Secure parameter ensures that the cookie can only be transmitted securely over HTTPS and will not be sent over unencrypted HTTP connections:

document.cookie = 'name=Flavio; Secure';

Note that adding the Secure parameter does not automatically make cookies secure. It is important to avoid including sensitive information in cookies.

HttpOnly

The HttpOnly parameter makes cookies inaccessible via the document.cookie API, ensuring they can only be edited by the server:

document.cookie = 'name=Flavio; Secure; HttpOnly';

SameSite

The SameSite attribute allows servers to require that a cookie is not sent on cross-site requests but only on resources that have the same domain as the cookie origin. This can help reduce the risk of CSRF (Cross-Site Request Forgery) attacks. Please note that SameSite is not supported by all browsers yet.

Updating and Deleting Cookies

To update the value or parameters of a cookie, simply assign a new value to the cookie name:

document.cookie = 'name=Flavio2';

To update the expiration date, reassign the value with a new expires or max-age property:

document.cookie = 'name=Flavio; max-age=31536000'; // Expires in 1 year

To delete a cookie, unset its value and pass a date in the past:

document.cookie = 'name=; expires=Thu, 01 Jan 1970 00:00:00 UTC;';

To access cookie values, use the document.cookie property:

const cookies = document.cookie;

To check if a cookie exists, you can use the following code:

// ES5
if (
  document.cookie
    .split(';')
    .filter(item => item.indexOf('name=') >= 0)
    .length
) {
  // Name exists
}

// ES2016
if (
  document.cookie
    .split(';')
    .filter(item => item.includes('name='))
    .length
) {
  // Name exists
}

Abstraction Libraries

There are various libraries available that provide a more user-friendly API for managing cookies. One popular library is js-cookie, which has good compatibility with older browsers and many stars on GitHub.

Here are some examples of using js-cookie:

Cookies.set('name', 'value');
Cookies.set('name', 'value', {
  expires: 7,
  path: '',
  domain: 'subdomain.site.com',
  secure: true
});

Cookies.get('name'); // Returns 'value'

Cookies.remove('name');

// JSON cookies
Cookies.set('name', { name: 'Flavio' });
Cookies.getJSON('name'); // Returns { name: 'Flavio' }

The decision to use a library like js-cookie or the native cookies API depends on your requirements and the additional kilobytes it will add for users to download.

Using Cookies Server-Side

Every server-side environment allows interaction with cookies because they are essential for the modern web. For example:

  • PHP has $_COOKIE.
  • Go has cookie facilities in the net/http standard library.

When using Express.js, you can create cookies using the res.cookie API:

res.cookie('name1', '1Flavio', {
  domain: '.example.com',
  path: '/admin',
  secure: true
});

res.cookie('name2', 'Flavio2', {
  expires: new Date(Date.now() + 900000),
  httpOnly: true
});

res.cookie('name3', 'Flavio3', { maxAge: 900000, httpOnly: true });

// Takes care of serializing JSON
res.cookie('name4', { items: [1, 2, 3] }, { maxAge: 900000 });

To parse cookies, you can use the cookie-parser middleware in Express.js. The req.cookie property of the Request object will contain the cookie information:

req.cookies.name; // Returns 'Flavio'
req.cookies.name1; // Returns 'Flavio1'

If you create cookies using signed: true, they will be available in the req.signedCookies object. Signed cookies prevent modifications on the client and allow the server to verify their integrity.

The express-session and cookie-session middleware provide options for building cookie-based authentication, depending on your specific needs.

Inspecting Cookies with Browser DevTools

All major browsers provide tools, such as DevTools, to inspect and edit cookies.

Chrome

Chrome DevTools Cookies

Firefox

Firefox DevTools Cookies

Safari

Safari DevTools Cookies

Alternatives to Cookies

Although cookies are widely used for authentication and sessions on the web, they are not the only option. The use of JSON Web Tokens (JWTs) has gained popularity. JWTs provide token-based authentication, which enables stateless authentication without the need for server-side sessions.

Tags: HTTP cookies, web development, cookies in HTML, cookies in JS, cookie management