Redis Server Sessions in Node

09.16.2021

Intro

Sessions are usually short lived data, or at least have an expiration date, used to transfer state accross RESTful applications. REST applications are stateless per their spec, yet sometimes we need to pass stateful data accross requests. Request sessions were used a lot before the days of single page applications, but they are still used in mostly application today.

For example, two main use case today are user sessions, where we allow a user to be logged in for a set duration, and OAuth, where we need to track state over a number of requests to log a user into an OAuth server.

For session management, you will need some database abstracted from your restful server so that you can scale the server on different machines. Redis is a great choice for this as it allows for you to easily expire data and is very fast, keeping your request response time quick.

In this article, we will learn how to use Redis to manage user sessions.

Getting Setup

Let's start by creating a folder and initializing our package.

touch express-session-example
cd express-session-example
touch index.js
npm init -y

Creating the Basic Server

Next, let's install express, open up our index.js file, and add a standard express route.

npm install express
const express = require('express');
const app = express();

app.get('/', function(req, res){
   res.send("Hello world!");
});

app.listen(3000);

Adding Express Session

Now, let's add the express session package and configure our server to use it.

npm install express-session

We can use express session by attaching it as middleware to express. Using this default implementation will use an in-memory session management, which is not scalable accross multiple servers, as they don't share memory. We will add redis soon to solve this.

app.use(session({
    secret: 'generate-a-secret-then-put-here',
    cookie: { maxAge: 60000 }
}))

Now, we can add variables to our sessions using the req.session varaible in express. Here is an example of adding a code to our request, which is similar to what you would use during an oauth flow.

const express = require('express');
const app = express();

app.use(session({
    secret: 'generate-a-secret-then-put-here',
    cookie: { maxAge: 60000 }
}));

app.get('/', function(req, res){
    if (req.session.code) {
        console.log("We have the code!")
    } else {
        req.session.code = 'my-code'
    }
    res.send("Hello world!");
});

app.listen(3000);

Adding in Redis

Now that we have seen how to setup express session, let's presist our session info to redis.

npm install redis connect-redis

We can replace the session code above with the following. This will allow us to store session data in our redis server instead.

const redis = require('redis')
const session = require('express-session')
const connectRedis = require('connect-redis')

const RedisStore = connectRedis(session)
const redisClient = redis.createClient()

app.use(
  session({
    store: new RedisStore({ client: redisClient }),
    saveUninitialized: false,
    secret: 'generate-a-secret-then-put-here',
    resave: false,
  })
)

Using Redis for PassportJS Authentication

Now, we can extend our usage of redis to be used for passportjs and authentication. I won't go through the full details of passport js as you can read their docs here: http://www.passportjs.org/docs/basic-digest/. However, when you get to the middleware section under Sessions, you will see an example similar to this.

app.configure(function() {
  app.use(express.static('public'));
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session({ secret: 'keyboard cat' }));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
});

We can alter this by adding in our redis config above.

app.configure(function() {
  app.use(express.static('public'));
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  
  app.use(
    session({
        store: new RedisStore({ client: redisClient }),
        saveUninitialized: false,
        secret: 'generate-a-secret-then-put-here',
        resave: false,
    })
    )

  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
});

And there we go! Now, we have redis storing our user sessions as well.