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.
Cookie Security
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;
Checking if a Cookie Exists
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
Firefox
Safari
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