Sending and Receiving Cookies from Express.js

Jack Misteli

Cookie management is not the most difficult thing to do in Express.js, but there are a lot of solutions out there to help you which can make things quite confusing. We’re going to look at a very raw implementation of cookies. If you want to learn more about what browser cookies are, I recommend reading this article first.

What We’re Building

We’re going to make a little grocery store application using Express.js and as little other libraries as possible. You can see my extremely boring implementation of it at temporas.laeeto.com To get started we will run:

$ npm init
$ npm install express body-parser cors

Our application will have an app.js file and a productDao.js file.

Module: app.js

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const productDao = require('./productDao.js');

// We will define this later
const sessionHandler = require('./sessionHandler');
const apiRouter = require('./apiRouter');
const app = express()

// Our API will be listening on port 4000
app.set('port', process.env.PORT || 4000)

// We support json requests
app.use(bodyParser.json())

// Allow cors everywhere
app.use(cors())

// This will manage our sessions
app.use(sessionHandler)

// Our app had one route to get the products in our database
app.use('/api', apiRouter)

// Launching our server on our app's port
const server = app.listen(app.get('port'), () => {
 console.log(`Shopping App is running on port ${app.get('port')}`)
})

export default server

Module: apiRouter.js

const router = require('express')

// Our app had one route to get the products in our database
app.get('/product/all', (req, res) => {

// This array simulates our database
const allProducts = [
  {name: 'blue cheese', type:'cheese'},
  {name: 'brocolli', type: 'vegetable'},
  {name: 'cookie', type: 'snack'}
 ];
 res.status(200).send(allOurProducts)
})

// add item to the cart
app.post('/cart', (req,res)=> {
 // We'll write this code later
})

// get all items in the shopping cart
app.post('/cart', (req,res)=> {
 // We'll write this code later
})

// Allows our user to checkout
app.post('/checkout', (req, res) => {
 // We'll write this code later
})

Sending Cookies in Express.js

Before looking at any other library, we can see that Express has a cookie property on the Response object.

Module: sessionHandler.js

// sentTokenCookie creates a cookie which expires after one day
const sendUserIdCookie = (userId, res) => {
 // Our token expires after one day
 const oneDayToSeconds = 24 * 60 * 60;
 res.cookie('userId', userId,  
 { maxAge: oneDayToSeconds,
 // You can't access these tokens in the client's javascript
   httpOnly: true,
   // Forces to use https in production
   secure: process.env.NODE_ENV === 'production'? true: false
  });
};

Getting Cookies in Express

A great utility is cookie-parser. You can use it to attach a new interface to your Express Request and Response instances. It is an extremely simple library and I highly recommend you check out the source code.

For learning purposes, we’ll use as few libraries as we can. But in your project you should use libraries like express-cookie to read the request’s cookies, express-session to manage sessions and || or cookie-parser to parse cookies.

Module: sessionHandler.js

// returns an object with the cookies' name as keys
const getAppCookies = (req) => {
 // We extract the raw cookies from the request headers
 const rawCookies = req.headers.cookie.split('; ');
 // rawCookies = ['myapp=secretcookie, 'analytics_cookie=beacon;']

 const parsedCookies = {};
 rawCookies.forEach(rawCookie=>{
 const parsedCookie = rawCookie.split('=');
 // parsedCookie = ['myapp', 'secretcookie'], ['analytics_cookie', 'beacon']
  parsedCookies[parsedCookie[0]] = parsedCookie[1];
 });
 return parsedCookies;
};

// Returns the value of the userId cookie
const getUserId = (req, res) =>  getAppCookies(req, res)['userId'];

Now that we know how to create and read session cookies, let’s create some sessions.

Unique Session IDs

In my opinion, the best tool in Node.js to get unique identifiers is the uuid package. We’ll assign one unique identifier to each client.

Module: sessionHandler.js

// Our application store is stateful and uses a variable
const sessions = {};

const sessionHandler = (req, res, next)=> {
 // extracting the user id from the session
 let userId = getUserId(req, res);

 // If we don't have a userId or the session manager doesn't recognize the userId
 // then we create a new one one
  if(!userId || !sessions[userId]) {
   // this should create a time based unique identifier
    userId = uuidv1();
    sessions[userId] = {
    cart: {}
  };
  // Clearing the cookies in case the session userid is not valid
  res.clearCookie('userId');
  // Returning the newly assigned cookie value
  sendUserIdCookie(userId, res);
 }

 req.session = sessions[userId];
 // Now in our route handlers you'll have session information in req.session
 next();
};

Writing Our Shopping Routes

Here’s the route definitions for our cart:

Module: apiRouter.js

router.get('/cart', (req, res) => {
 // Returns the value of the cart
 const cart = req.session.cart;
 res.status(200).send(cart);
});

router.post('/cart', (req, res) => {
 const cart = req.session.cart;
 const productName = req.body.productName;

 // Fancy stupid trick to do create a key with the value 1
 // or if the key exists increment the value by 1
 cart[productName] = -~ cart[productName];
 return res.status(200).send('success');
});

router.post('/checkout', (req, res)=> {
 // We want to clear the cookies
 res.clearCookie('userId');
});

module.exports = router;

You might have noticed that the application’s management is stateful. This means that if the server reloads we loose all of our sessions. That’s why we’ll want to use JWT tokens or Redis to make it stateless.

🍪🍪🍪 That's it for today! Feel free to ask us questions on Twitter. 🍪🍪🍪

  Tweet It

🕵 Search Results

🔎 Searching...