Session Management in Nodejs Using Redis as Session Store

Chamith Madusanka
The Startup
Published in
7 min readNov 8, 2020

Why we need sessions

The classic Hypertext Transfer Protocol (HTTP) is a stateless tool. This means every request that is sent from a single client is interpreted by the Web server independently and is not related to any other request. There is no inbuilt mechanism for the server to remember a specific user from different multiple requests, which also makes it impossible for the server to know if each request originated from the same user.

HTTP Sessions

Session tracking enables you to track a user’s progress over multiple servlets or HTML pages, which, by nature, are stateless. A session is defined as a series of related browser requests that come from the same client during a certain time period. Session tracking ties together a series of browser requests — think of these requests as pages — that may have some meaning as a whole, such as a shopping cart application.

There are few types of session storing techniques

  • Memory (single-server, non-replicated persistent storage)
  • File system persistence
  • JDBC persistence
  • Cookie-based session persistence
  • In-memory replication

Here we are using the Memory (single-server, non-replicated persistent storage) to manage sessions. When you use memory-based storage, all session information is stored in memory and is lost when you stop and restart. Better to use a external persistence storage.

We are creating the session in our session store and the session ID is sent back to the client in a Cookie. Then this Cookie can be passed to server with each and every request to identify the particular client.

How web sessions work

Session management in NodeJs

We can use express-session middleware to manage sessions in Nodejs. The session is stored in the express server itself. The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing. To manage multiple sessions for multiple users we have to create a global map and put each session object to it. Global variables in NodeJs are memory consuming and can prove to be terrible security holes in production level projects.

This can be solved by using external Session Store. We have to store every session in the store so that each one will belong to only a single user. One popular session store is built using the Redis.

What we are building

We are building a simple user login using the sessions.

  1. User login to the application by entering the username and the password.
  2. After submitting the server generates a unique random number, known as the session ID, which is also stored on the Reids store.
  3. The session ID is sent back to the user in the cookie header of the response data. For Node.js, this cookie header is named connect.sid.
  4. Next time user comes to the application, the cookie is passed back to the server in the header with the session id. Then server check for the particular session id in the Redis store. If the session exists in the store user will be redirected to the home page without going to the login page.
  5. User can stay in the page until the session expires.

Implementation

  • Setup the Redis server on you PC.
  • Create a Nodejs project and add following dependencies.
npm install express express-session redis connect-redis
  • Now you can setup the Redis client and session middleware in the index.js file.
const express = require('express');
const session = require('express-session');
const redis = require('redis');
const connectRedis = require('connect-redis');
var bodyParser = require('body-parser');
const app = express();app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// enable this if you run behind a proxy (e.g. nginx)
app.set('trust proxy', 1);
const RedisStore = connectRedis(session)//Configure redis client
const redisClient = redis.createClient({
host: 'localhost',
port: 6379
})
redisClient.on('error', function (err) {
console.log('Could not establish a connection with redis. ' + err);
});
redisClient.on('connect', function (err) {
console.log('Connected to redis successfully');
});
//Configure session middleware
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'secret$%^134',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // if true only transmit cookie over https
httpOnly: false, // if true prevent client side JS from reading the cookie
maxAge: 1000 * 60 * 10 // session max age in miliseconds
}
}))
  • To add support of Redis you have to use Redis client and connect-redis. Create express-session and pass it to connect-redis object as parameter. This will initialize it. Then in session middleware, pass the Redis store information such as host, port and other required parameters.
  • Now I'm adding following endpoints to index.js file to build the logic I have explained above.
app.get("/", (req, res) => {
const sess = req.session;
if (sess.username && sess.password) {
if (sess.username) {
res.write(`<h1>Welcome ${sess.username} </h1><br>`)
res.write(
`<h3>This is the Home page</h3>`
);
res.end('<a href=' + '/logout' + '>Click here to log out</a >')
}
} else {
res.sendFile(__dirname + "/login.html")
}
});
app.post("/login", (req, res) => {
const sess = req.session;
const { username, password } = req.body
sess.username = username
sess.password = password
// add username and password validation logic here if you want.If user is authenticated send the response as success
res.end("success")
});
app.get("/logout", (req, res) => {
req.session.destroy(err => {
if (err) {
return console.log(err);
}
res.redirect("/")
});
});
  • Like this you can set any value to session object. Those data will be persisted in the session store for that specific user. If another user comes data will be saved to that specific user’s session.
const sess = req.session;
const { username, password } = req.body
sess.username = username
sess.password = password
  • This will remove the session object from the session store.
req.session.destroy
  • login.html
<html>
<head>
<title>User Login</title>
</head>
<body>
Username:
<input type="text" id="username" /><br />
Password :
<input type="password" id="password" /><br />
<input type="button" value="Submit" id="submit" />
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
jQuery(document).ready(function ($) {
$("#submit").click(function () {
let username = $("#username").val();
let password = $("#password").val();
$.post(
"/login",
{ username: username, password: password },
function (data) {
if (data === "success") {
window.location.href = "/";
}
}
);
});
});
</script>
</html>
  • package.json file
{
"name": "nodejs-session-redis",
"version": "1.0.0",
"description": "Implement session store for express using redis",
"main": "index.js",
"scripts": {
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Chamith Madusanka",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"connect-redis": "^5.0.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"nodemon": "^2.0.6",
"redis": "^3.0.2"
}
}

Let’s run the code!

  • Now all set to go. You can run npm start in the terminal to start the application. Then you can see the following message in the console.
Login page
  • Login to the application by submitting the form.
Home page
  • Now you can see a cookie has been created and sent back to the browser. Go to your browser, press f12 and see the Application section for the cookies.
Cookie sent from the server
  • Also you can go to redis-cli check the session created by server for the particular user by executing this command.
KEYS *
Session create in the Redis store
  • Now if you go to http://localhost:3000/ again, you will be redirected to home page because the server has previously created session.
  • Session is valid until the maxAge time you defined in the session store configuration. After that session will be automatically removed from the session store. Also you can log out from the application and check for the same key. It should not be there.
  • If you try with a different browser to mimic another session, you will see another session created in Redis.

That is it. The express session with Redis store is working.

Conclusion:

Redis is one of the popular key storage database systems. Using it to store session is not only beneficial in production environment but also it helps to improve the performance of the system.

I have uploaded the working sample of my project to the GitHub. You can download from here.

Thank you for reading this post. If you do have any questions please add as a comment. I will definitely answer your questions. If you like this post, give a Cheer!!!

Happy Coding ❤

--

--

Chamith Madusanka
The Startup

Full Stack Enthusiast | JavaScript | TypeScript | NodeJs | NestJs | ReactJs | NextJs | Java | https://www.linkedin.com/in/chamith24/