Session Management in Node.js

Session management is a mechanism to persist user data across multiple requests in a web application. It is essential for implementing features like user authentication, shopping carts, and personalized user experiences.

Setting Up the Project

First, create a new directory for your project and initialize it with npm:

				
					mkdir session-management
cd session-management
npm init -y

				
			

Install the necessary packages:

				
					npm install express express-session cookie-parser redis connect-redis mongoose connect-mongo

				
			

Using Cookies for Session Management

Cookies are small pieces of data stored on the client side. They can be used to store session data.

File: cookie-session.js

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

const app = express();
const PORT = 3000;

// Use cookie-parser to parse cookies
app.use(cookieParser());

// Middleware to check and set a cookie
app.use((req, res, next) => {
    if (!req.cookies.user) {
        res.cookie('user', 'John Doe', { maxAge: 900000, httpOnly: true });
    }
    next();
});

app.get('/', (req, res) => {
    res.send(`Hello, ${req.cookies.user || 'Guest'}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Output:

When you visit http://localhost:3000 for the first time, the server will set a cookie named user with the value John Doe. On subsequent visits, the server will read this cookie and greet the user by name.

Session Management with express-session

The express-session middleware is a robust, flexible solution for session management in Express applications.

File: session-management.js

				
					const express = require('express');
const session = require('express-session');

const app = express();
const PORT = 3000;

app.use(session({
    secret: 'mysecret', // Secret used to sign the session ID cookie
    resave: false,      // Do not save session if unmodified
    saveUninitialized: true, // Save uninitialized session
    cookie: { secure: false } // Set to true if using HTTPS
}));

app.get('/', (req, res) => {
    if (!req.session.user) {
        req.session.user = 'John Doe';
    }
    res.send(`Hello, ${req.session.user}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Output:

When you visit http://localhost:3000, the server will create a session for the user and store their name. On subsequent visits, the server will read the session data and greet the user by name.

Storing Sessions in a Database

For scalability and persistence, storing sessions in a database is a common approach. We’ll explore using Redis and MongoDB for this purpose.

Using Redis for Session Storage

Redis is an in-memory data structure store that is ideal for session storage due to its speed and support for data persistence.

File: redis-session.js

				
					const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');

// Create a Redis client
const redisClient = redis.createClient();

const app = express();
const PORT = 3000;

app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false }
}));

app.get('/', (req, res) => {
    if (!req.session.user) {
        req.session.user = 'John Doe';
    }
    res.send(`Hello, ${req.session.user}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Output

When you visit http://localhost:3000, the server will store the session data in Redis. On subsequent visits, the session data will be retrieved from Redis, ensuring persistence across server restarts.

Using MongoDB for Session Storage

MongoDB is a popular NoSQL database that can also be used for session storage.

File: mongodb-session.js

				
					const express = require('express');
const session = require('express-session');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/sessionDB', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

const app = express();
const PORT = 3000;

app.use(session({
    store: new MongoStore({ mongooseConnection: mongoose.connection }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false }
}));

app.get('/', (req, res) => {
    if (!req.session.user) {
        req.session.user = 'John Doe';
    }
    res.send(`Hello, ${req.session.user}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Output: When you visit http://localhost:3000, the server will store the session data in MongoDB. On subsequent visits, the session data will be retrieved from MongoDB, ensuring persistence across server restarts.

Securing Sessions

To enhance security, consider the following best practices:

  • Use HTTPS: Ensure cookies are only sent over HTTPS.
  • Set Secure and HttpOnly Flags: These flags protect cookies from being accessed by client-side scripts.
  • Regenerate Session IDs: Regularly regenerate session IDs to prevent session fixation attacks.

File: secure-session.js

				
					const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');

const redisClient = redis.createClient();

const app = express();
const PORT = 3000;

app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: true, httpOnly: true } // Secure and HttpOnly flags
}));

app.get('/', (req, res) => {
    if (!req.session.user) {
        req.session.user = 'John Doe';
    }
    res.send(`Hello, ${req.session.user}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Advanced Topics in Session Management

Implementing Remember Me Functionality

“Remember Me” functionality allows users to stay logged in for extended periods.

File: remember-me.js

				
					const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');

const redisClient = redis.createClient();

const app = express();
const PORT = 3000;

app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 } // 1 day
}));

app.get('/login', (req, res) => {
    req.session.user = 'John Doe';
    res.send('Logged in!');
});

app.get('/logout', (req, res) => {
    req.session.destroy((err) => {
        if (err) {
            return res.status(500).send('Failed to logout.');
        }
        res.send('Logged out!');
    });
});

app.get('/', (req, res) => {
    res.send(`Hello, ${req.session.user || 'Guest'}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Handling Session Expiry

Sessions should expire after a certain period of inactivity to enhance security.

File: session-expiry.js

				
					const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');

const redisClient = redis.createClient();

const app = express();
const PORT = 3000;

app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false, maxAge: 15 * 60 * 1000 } // 15 minutes
}));

app.get('/', (req, res) => {
    if (!req.session.user) {
        req.session.user = 'John Doe';
}
    res.send(Hello, ${req.session.user}!);
});

app.listen(PORT, () => {
console.log(Server running on port ${PORT});
});
				
			

Output:

When you visit `http://localhost:3000`, the server will create a session that expires after 15 minutes of inactivity. On subsequent visits within the 15-minute window, the session data will be retrieved, ensuring the user remains logged in.

Regularly regenerating session IDs helps prevent session fixation attacks.

File: `regenerate-session.js`

				
					const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');

const redisClient = redis.createClient();

const app = express();
const PORT = 3000;

app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false }
}));

app.get('/login', (req, res) => {
    req.session.regenerate((err) => {
        if (err) {
            return res.status(500).send('Failed to regenerate session.');
        }
        req.session.user = 'John Doe';
        res.send('Session regenerated and user logged in!');
    });
});

app.get('/', (req, res) => {
    res.send(`Hello, ${req.session.user || 'Guest'}!`);
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});
				
			

Output:

When you visit http://localhost:3000/login, the server will regenerate the session ID and set the user data. On subsequent visits, the session data will be retrieved using the new session ID, preventing fixation attacks.

Practical example : User Authentication with Session Management

Let’s create a full practical example of a Node.js application that implements session management with user authentication. We’ll use express-session for managing sessions, bcrypt for hashing passwords, and connect-mongo to store session data in MongoDB.

Setting Up the Project

First, create a new directory for your project and initialize it with npm:

				
					mkdir auth-session-example
cd auth-session-example
npm init -y

				
			

Installing Dependencies

Install the necessary packages:

				
					npm install express express-session bcrypt mongoose connect-mongo

				
			

Setting Up MongoDB

Make sure you have MongoDB running locally. You can start it using:

				
					mongod

				
			

Creating the User Model

We’ll create a simple User model with Mongoose. This will be used to store user credentials.

File: models/User.js

				
					const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const userSchema = new mongoose.Schema({
    username: { type: String, required: true, unique: true },
    password: { type: String, required: true }
});

// Pre-save hook to hash passwords before saving
userSchema.pre('save', async function(next) {
    if (this.isModified('password') || this.isNew) {
        const salt = await bcrypt.genSalt(10);
        this.password = await bcrypt.hash(this.password, salt);
    }
    next();
});

// Method to compare passwords
userSchema.methods.comparePassword = function(candidatePassword) {
    return bcrypt.compare(candidatePassword, this.password);
};

module.exports = mongoose.model('User', userSchema);

				
			

Setting Up Express with Sessions

Now, we’ll set up the main server file to handle user registration, login, and logout.

File: server.js

				
					const express = require('express');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const User = require('./models/User');

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/authSessionDB', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

const app = express();
const PORT = 3000;

app.use(express.urlencoded({ extended: true }));

// Set up session middleware with MongoDB storage
app.use(session({
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    store: new MongoStore({ mongooseConnection: mongoose.connection }),
    cookie: { secure: false } // Set to true in production with HTTPS
}));

// Middleware to check if user is authenticated
function isAuthenticated(req, res, next) {
    if (req.session.user) {
        return next();
    }
    res.redirect('/login');
}

// Route to serve the homepage
app.get('/', isAuthenticated, (req, res) => {
    res.send(`Hello, ${req.session.user.username}! <a href="/logout">Logout</a>`);
});

// Route to handle user registration
app.post('/register', async (req, res) => {
    const { username, password } = req.body;
    try {
        const newUser = new User({ username, password });
        await newUser.save();
        req.session.user = newUser;
        res.redirect('/');
    } catch (err) {
        res.send('Registration failed. Username might already be taken.');
    }
});

// Route to serve the registration page
app.get('/register', (req, res) => {
    res.send(`<form method="post" action="/register">
                Username: <input type="text" name="username" required><br>
                Password: <input type="password" name="password" required><br>
                <button type="submit">Register</button>
              </form>`);
});

// Route to handle user login
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    const user = await User.findOne({ username });
    if (user && await user.comparePassword(password)) {
        req.session.user = user;
        res.redirect('/');
    } else {
        res.send('Invalid username or password.');
    }
});

// Route to serve the login page
app.get('/login', (req, res) => {
    res.send(`<form method="post" action="/login">
                Username: <input type="text" name="username" required><br>
                Password: <input type="password" name="password" required><br>
                <button type="submit">Login</button>
              </form>`);
});

// Route to handle user logout
app.get('/logout', (req, res) => {
    req.session.destroy((err) => {
        if (err) {
            return res.status(500).send('Failed to logout.');
        }
        res.redirect('/login');
    });
});

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

				
			

Running the Application

Start MongoDB if it’s not already running:

				
					mongod

				
			

Run your Node.js application:

				
					node server.js

				
			

Testing the Application

You can test the application by visiting the following URLs:

  • Registration: Go to http://localhost:3000/register and create a new user account.

    Output: After submitting the registration form, you will be logged in and redirected to the homepage, which will greet you by username.

  • Login: If you log out or restart the server, go to http://localhost:3000/login to log back in.

    Output: After submitting the login form with valid credentials, you will be logged in and redirected to the homepage.

  • Logout: Click the “Logout” link on the homepage to end your session.

    Output: You will be logged out and redirected to the login page.

User Model (User.js):

  • Defines the schema for the User, including methods for hashing passwords before saving them and comparing hashed passwords for authentication.

Express Server (server.js):

  • Sets up express-session with connect-mongo to store sessions in MongoDB.
  • Includes routes for user registration, login, and logout.
  • Uses middleware to protect routes and ensure only authenticated users can access certain pages.

Session Management:

  • When a user registers or logs in, their session is created, and their user information is stored in the session.
  • Session data is persisted in MongoDB, so even if the server restarts, the session remains valid until it expires or the user logs out.

Session management is a crucial aspect of developing secure and user-friendly web applications. This chapter covered the basics of session management using cookies and express-session, and advanced topics like using Redis and MongoDB for session storage, securing sessions, implementing "Remember Me" functionality, handling session expiry, and regenerating sessions. By following these practices, you can ensure a robust session management system for your Node.js applications.Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India