When I started learning about sessions and their meaning it wasn’t easy to understand what is the correct flow and how things should be configured to make sessions work.
As a Full Stack Developer at Joonko, we had to start working on a new version of the company’s product and we had to implement an ability for users to sign in to the system and do some actions, and for that, we had to implement sessions in our backend server.
How do sessions work?
When a user logs in to a system and makes a login request to the server, the server will create a session and store it on the server’s local cache or in external storage (database).
Then, after finishing this process, the server responds to the client with a cookie.
The cookie usually contains a unique ID which is the session id and will be stored on the client browser for a limited time.
From this point, every request that will be sent to the server will include the browser cookies including the session cookie.
About express-session:
express-session is an HTTP server-side framework that can be used to create and manage a session middleware, this package will be our main thing for this tutorial.
Set up a project:
Use the following command to initialize a NodeJS project:
npm init -y
Next, use the following command to install express and express-session:
npm install express express-session connect-mongo
Next, create a new file named app.js and add the following code to it:
const express = require('express');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const app = express();
app.use(session({
name: 'example.sid',
secret: 'Replace with your secret key',
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 * 7,
resave: false,
saveUninitialized: true,
store: MongoStore.create({
mongoUrl: 'MongoDB URL should be here'
})
}));
app.listen(4000, () => {
console.log("App listening on port 4000")
})
Explanation:
- We’ve created a new instance of express server and initialized a variable called app with it.
- Next, we’ve added a session middleware to the application server with the following configuration:
- name: The name of the cookie that will be stored on the client-side.
- secret: This is the secret used to sign the ID cookie.
- httpOnly: Specifies the value of httpOnly Set-Cookie attribute.
- secure: Specifies the value of secure Set-Cookie (note that this one will work only if you are using HTTPS on your environment).
- maxAge: Specifies the cookie’s max-age in milliseconds, I’ve already set it to 7 hours.
- resave: Forces the session to be saved back to the session store.
- saveUnitialized: Forces a session that is “uninitialized” to be saved to the session store.
- store: Uses MongoDB store which was implemented byconnect-mongo
NPM library and which you can view here and describes the connection between it. - Initializing a server and listening to port 4000.
Next, all we have to do is to implement a few routes that will use the middleware we created above.
In the following examples, I’ll create very simple routes just so you can understand better the usage of this middleware.
<POST> Create User Route
app.post('/', async (req, res, next) => {
const {name} = req.body;
req.session.user = {
name,
isLoggedIn: true
}
try {
await req.session.save();
} catch (err) {
console.error('Error saving to session storage: ', err);
return next(new Error('Error creating user'));
}
res.status(200).send();
})
The following route handles a POST request with a name in the request’s body, it enriches the request session’s user data and saves the updated session into the MongoDB sessions collection using the req.session.save method.
<POST> Logout User Route
app.post('/logout', async (req, res, next) => {
try {
await req.session.destroy();
} catch (err) {
console.error('Error logging out:', err);
return next(new Error('Error logging out'));
}
res.status(200).send();
})
The following route handles a POST request and everything it does is to destroy the current user’s session — which means that it will remove the session from the MongoDB sessions collection as well as delete the session cookie from the user’s browser.
<GET> User Full Name Route
app.get('/name', (req, res) => {
let name;
if (!req.session) {
return res.status(404).send();
}
name = req.session.user.name;
return res.status(200).send({name});
})
The following route handles GET request and return the full name of a user from his session data if it exists.
If you followed all the steps and did it all correctly, then it means that you will be able to access req.session object which will include everything you included in it the last time you used the save method.
If you want to learn more, lookup for my previous articles: