Express Cookies

Using Express Cookies

Express Cookies

by John Vincent


Posted on July 05, 2017



Handling Cookies for an Express App

Straightforward stuff, so let us begin.

NPM Cookie-parser

npm cookie-parser

Configure

Define the name of the application cookie.

config/config.js

exports.COOKIE_NAME = 'my-app-cookie-name';

Access

I consider this to be middleware. Thus

config/middleware.express.js

const cookieParser = require('cookie-parser');

...

app.use(cookieParser());

List Cookies

config/middleware.express.js

const listCookies = (req, res, next) => {
    console.log('Cookies: ', req.cookies);  // Cookies that have not been signed
    console.log('Signed Cookies: ', req.signedCookies); // Cookies that have been signed
    next();
};

List the Request

config/middleware.express.js

const logRequest = (req, res, next) => {
    const logObj = {
        time: (new Date()).toTimeString(),
        method: req.method,
        hostname: req.hostname,
        path: req.path,
        "content type": req.get('Content-Type'),
        query: JSON.stringify(req.query),
        body: JSON.stringify(req.body)
    };
    Object.keys(logObj).forEach(key => console.log(`request ${key}: ${logObj[key]}`));
    next();
};

...

app.use(cookieParser());

app.all('/', logRequest);
app.all('/', listCookies);

app.use(cookieParser())

  • parses request cookies,
  • populating req.cookies
  • when the secret is passed, populates req.signedCookies
    • secret is used for signing the cookies.

For a signed cookie

app.use(cookieParser('my secret here'));

General rule for setting cookie maxage

maxage = number of days * 24 hours * 60 minutes * 60 seconds * 1000 milliseconds

The application can create a cookie upon successful login.

if (remember) {
    const cookie_options = {
        maxAge: 1000 * 60 * 15,      // would expire after 15 minutes
        httpOnly: false,             // The cookie only accessible by the web server
        signed: false                // Indicates if the cookie should be signed
    };
    res.cookie(COOKIE_NAME, email, cookie_options);
}

When the response is sent, the cookie will be sent with the response.

For example, here the cookie is sent with a token.

const filtered_user = { 
    id: user.id,
    username: user.username
};

const token = jwt.sign(filtered_user, AUTHENTICATION_KEY, {
    expiresIn: 60 * 60
});
return res.status(200).json({ token });

Another use case

app.get('/', (req, res) => {
    let cookie = req.cookies[cookieName];
    if (req.cookies[cookieName] === undefined) {
        res.cookie(cookieName, 'my-value', cookie_options);
        console.log('cookie created successfully');
    }
    else {
        console.log('Cookie found, value is', cookie);
    }
    res.sendFile(__dirname + '/views/index.html');
});
  • res.clearCookie(COOKIE_NAME);

During development, I like to use an endpoint to delete a cookie. For example:

app.get('/forget-cookie', (req, res) => {
    res.clearCookie(COOKIE_NAME);
    res.send('cookie cleared');
});

JavaScript Client

There are some packages that make this a little easier, but let’s go native.

List Cookies

function listCookies() {
    var allcookies = document.cookie;
    var cookiearray  = allcookies.split(';');
    for (var i = 0; i < cookiearray.length; i++) {
        name = cookiearray[i].split('=')[0];
        value = cookiearray[i].split('=')[1];
        console.log("Key is : " + name + " and Value is : " + value);
    }
}

Get Cookie value. This method requires a cookie name. The value is retrieved and decoded.

function getUsernameFromCookie(cookieName) {
    var allcookies = document.cookie;
    var cookiearray = allcookies.split(';');
    for (var i = 0; i < cookiearray.length; i++) {
        var name = cookiearray[i].split('=')[0];
        if (cookieName === name.trim()) {
            return decodeURIComponent(cookiearray[i].split('=')[1]);
        }
    }
    return '';
}

Using a real example. A login form should get the username from the cookie, if it exists.

$(function() {
    $("#email").focus();

    var cookie_email = getUsernameFromCookie('my-app-cookie');
    $('#email').val(cookie_email);
});

When the page loads, get the value of the cookie ‘my-app-cookie’ and copy it to the email address field.

The signed property is true.

Thus

if (remember) {
    const cookie_options = {
        maxAge: 1000 * 60 * 15,
        httpOnly: false,
        signed: true
    };
    res.cookie(COOKIE_NAME, email, cookie_options);
}

The cookie will still be visible, but it has a signature, so it can detect if the client modified the cookie.

It works by creating a HMAC of the value (current cookie), and base64 encoded it. When the cookie gets read, it recalculates the signature and makes sure that it matches the signature attached to it.

If it does not match, it will give an error.

To access a signed cookie

req.signedCookies['name']