Published on

All About Cookies

Authors
  • avatar
    Name
    David Rhodes
    Twitter
cookie being made

What's the big deal about cookies? HTTP cookies, aka "magic" cookies, are the handshake that makes communicating between a server and a client possible. In this article we'll explore exactly what they are, why they are used, and how they are made.

What's a Cookie?

Cookies are small text files comprised of name/value pairs in a string. For example, you can set them in Javascript with:

document.cookie = "username=JohnDoe"

Cookies are passed between server and client and upon return calls from client to server. And, cookies can be set or read server side, or client side (as long as the httpOnly flag is set to "false"). You can view a browser's cookies by looking in your browser's dev tools under the Applications tab, Storage section:

cookies in dev tools

Lou Montulli, a web programmer for Netscape, came up with the cookie architecture in 1994 when he needed a way to remember their client MCI's e-commerce carts. Which leads to one of the main reasons why cookies were used...

Why Use Cookies?

Cookies are used to enhance end web users' experience, by monitoring or remembering them. HTTP is designed as a stateless protocol, so state information is not retained between server calls by default. In the above MCI example, cookies served to remember the user's cart so they could return to a shopping experience later without it forgetting their items. Some other ways client side storage is used to enhance a user's web experience are:

  • UI preferences, like light/dark mode;
  • Authentication, or login;
  • Authorization, aka role-based content access;
  • Personalization
  • Recommendations
  • Tracking browser activity, purchases, product preferences, IP address, geolocation, etc. for more targeted advertising

Cookies can be thought of as a coded wristband you're assigned at a music festival or amusement park. It can be used to match your identity, wallet, emergency contact, and purchase preferences -- all personal details designed to enhance your user experience.

Cookies vs. Sessions

There's a distinction you may find helpful as cookies and sessions are very similar. The difference between cookies and sessions is simple: Cookies store user information on the client, and sessions store user information on the server. Session data is available for all pages served by the site. The reason you'd want to store information server-side is because you can validate it, therefore manipulate and sanitize it.

There are two ways to implement sessions:

  1. Store everything on the cookie.
  2. Store a unique ID in the cookie and the remaining data points on the server.

#2 is the recommended way to implement sessions.

Notice in the dev tools image above in the Storage section there are multiple listings. IndexedDB, Local Storage, and Session Storage APIs are increasingly used more than Cookies for storing user data client-side, while Cookies are increasingly used more to store Session IDs because of size constraints (cookies only store 4kb). Cookies are also limited in their total number and new ones replace oldest ones when the maximum number is reached.

Arguments Against Cookies

Perhaps no other area of web architecture has been more hotly contested than that of cookies. Cookies that follow your behavior across the web have been known to track hundreds of data points about users, although nothing that's personally identifiable. The Cambridge Analytica/Facebook Scandal is a perfect example of such targeted advertising gone horribly wrong.

And cookies are one of the most commonly-exploited vectors for hackers. Decoding cookies, session hijacking, and session fixation are all ways cookies can be exploited to hack users.

Government regulation has stepped in to ensure consumers are at least notified about cookies and the information tracked. The European Union instituted the GDPR, or General Data Protection Regulation, in 2018. In the same year, California passed the CCPA, or California Consumer Privacy Act. Both cover the right-to-know what is being tracked and the right-to-opt-out of tracking. As a result, a cottage industry around compliance to the new regulations sprung up.

How to Set Cookies

Cookies are passed between the server and client, and as such, can be set by the server or client. Your back-end can be coded in a variety of languages including PHP, Python, and Node.js. As a Javascript engineer, I'll use Node.js and Express. Express is a "Node application framework" that abstracts the building and maintenance of a Node.js server. Using Express, we can set, adjust, and delete cookies from each route. So let's create a bare-bones app to demonstrate how to work with cookies. First we'll install the libraries express, dayjs and cookie-parser:

npm install express cookie-parser dayjs

Then, in your project's index.js file, let's set up the express boilerplate:

const express = require("express")
const cookieParser = require("cookie-parser")
const dayjs = require("dayjs");
const app = express()
app.use(cookieParser())

Then, set up the home route with a cookie:

app.get("/", (req, res) => {
  res.cookie("darkmode", "true", {
      secure: process.env.NODE_ENV !== "development",
      httpOnly: true,
      expires: dayjs().add(30, "days").toDate(),
    });

  res.send("Hello.");

})

app.listen(3000);

A few things are happening here after setting up the server; I'll explain then illustrate how they show up in dev tools. First and most importantly, we're setting a cookie with the name/value pair of "darkmode"/"true". Then we are protecting that information by setting the secure flag to a boolean depending on whether it's development mode or not (this is for learning purposes; we'd more than likely not protect UI information like dark mode!). Next, we're setting httpOnly to true to ensure there are no cross-site scripting attacks by guaranteeing the cookie can only be read by this client and server, no others. And finally, we're setting this cookie to the browser cache for 30 days with the expires flag.

Now run the app by entering node index.js in the console, and navigate your browser to http://localhost:3000/. You should see "Hello" in the browser. Open dev tools and click on the Application tab, Storage section and you should see the flags set noted as below:

cookie set in dev tools

How to Read Cookies

Two great libraries to use for reading cookies with Express are cookie-parser and express-cookie. For learning purposes let's go under the hood though and demonstrate a helper function for setting all the request's cookies into an object with name/value properties:

const getCookies = (req) => {
  const cookies = req.headers.cookie.split('; ');
  const parsedCookies = {};

  cookies.forEach(rawCookie => {
    const parsedCookie = rawCookie.split('=');
    parsedCookies[parsedCookie[0]] = parsedCookie[1];
  });

  return parsedCookies;
};

How to Update Cookies

Just update the property as the second parameter for the res.cookie method. Note you need to include the previous options as the third object properties if you want to maintain them. Try the new route in your app and check dev tools to ensure the darkmode property is set to false, while HttpOnly and Secure are checked.

app.get('/set_lightmode_cookie', function (req, res) {
  res.cookie('darkmode', 'false', {
    secure: process.env.NODE_ENV !== 'development',
    httpOnly: true,
    expires: dayjs().add(30, 'days').toDate(),
  });
  res.send('cookie lightmode set');
});

How to Delete Cookies

Deleting Cookies with Express is easy. There are two approaches, deleting by value name, or deleting all. Deleting by value name:

app.get('/clear_darkmode_cookie', function (req, res) {
  res.clearCookie('darkmode');
  res.send('cookie darkmode cleared');
});

To delete all cookies, just use the clearCookie method without a name parameter:

res.clearCookie();

You can then visit the route and check to ensure the cookies are indeed gone.

Best Practices

  • Avoid storing sensitive information, such as passwords, as cookies are stored in plain text.
  • Restrict the cookie to only your application by using the path argument.
  • Don't share with subdomains: Use the domain option.
  • Only for secure connections: Using the secure option you can tell the browser (or other http clients) to only send the cookie over SSL connections.
  • Protect against XSS exploits: The httpOnly flag is used to tell the browser that it should not allow Javascript to access the contents of the cookie.

A typical snippet:

res.cookie('name', 'Tobias', {
  domain: '.example.com',  // Domain name for cookie - Defaults to app domain name
  path: '/admin', // Path for the cookie - Defaults to '/'
  secure: true, // cookies will be sent to server only on https
  httpOnly: true // Javascript client cannot read this cookie
});

Summary

Cookies are used to enhance the security and user experience of web users. While the root of controversy around privacy, recent legislative initiatives have provided some relief and will more than likely go global. Creating, reading, updating, and deleting cookies are easy with Express, a Node.js server framework. Nowadays, because of alternatives and storage contraints, cookies are used mostly for session IDs. Now you've got some answers when asked about cookies from an historic, architectural, and coding standpoint.