Lesson 2
Session Management with Express in NestJS
Session Management with Express

Welcome back to the Securing and Testing Your MVC NestJS App course! In this lesson, we will focus on session management, a key concept for maintaining user state across multiple requests. By the end of this lesson, you’ll know how to set up session management using Express in a NestJS application and interact with session data through controllers.

Understanding session management is crucial as it lays the groundwork for more advanced session-based authentication techniques, such as those using Passport.js. In the next lesson, we will explore how to integrate Passport.js for implementing secure, session-based authentication in your NestJS application.

What are Sessions?

A session allows a server to store information about a user that persists across multiple requests. This is important because HTTP, the protocol used for web communication, is stateless—meaning each request a user makes is independent of the previous ones. Sessions provide a way to link these independent requests by storing a small amount of data (like user identity, activity, etc.) on the server and associating it with a unique session ID stored in the user's browser (usually as a cookie).

In this lesson, we'll set up session management with Express in NestJS and track a user’s visits to a page.

Setting Up Session Management

In this section, we will install the necessary packages for managing sessions in our NestJS application using Express middleware.

Install the Required Packages

To handle session management in a NestJS application with Express, you need to install express-session and @nestjs/platform-express.

Run the following command:

Bash
1npm install express-session @nestjs/platform-express

Explanation:

  • express-session: This is the main middleware for managing sessions in Express. It will allow you to store and manage session data across requests.
  • @nestjs/platform-express: This package provides the integration for NestJS to work with Express and is necessary for applying middleware like express-session.

Once these packages are installed, you're ready to integrate session management into your application.

Initial Setup

We start by creating an Express-based NestJS application and configuring session middleware. For view rendering, we’ll use Handlebars. Here’s the setup:

TypeScript
1import { NestFactory } from '@nestjs/core'; 2import { AppModule } from './app.module'; 3import { NestExpressApplication } from '@nestjs/platform-express'; 4import { join } from 'path'; 5import * as hbs from 'hbs'; 6import * as session from 'express-session'; 7 8async function bootstrap() { 9 // Create an instance of NestExpressApplication to use Express-specific middleware 10 const app = await NestFactory.create<NestExpressApplication>(AppModule); 11 12 // Set Handlebars as the view engine and configure paths for views and partials 13 app.setBaseViewsDir(join(__dirname, '..', 'views')); 14 app.setViewEngine('hbs'); 15 hbs.registerPartials(join(__dirname, '..', 'views/partials')); 16 17 // Trust proxy settings (important when running behind a reverse proxy like Nginx) 18 app.set('trust proxy', 1);

Here’s what is happening:

  1. NestExpressApplication: This allows us to use Express middleware like session handling in our NestJS app.
  2. Handlebars Setup: We set up Handlebars as our view engine, specifying where the views and partials (reusable view fragments) are located.
  3. Trust Proxy: This is important if the app is behind a proxy like Nginx. It ensures that session cookies and headers are handled correctly, especially when using secure connections (HTTPS). (This is required for the CodeSignal environment.)
Configuring Session Middleware

Next, we configure the session middleware using the express-session package. This middleware will manage session data across user requests.

TypeScript
1 // Set up session middleware with custom configuration 2 app.use( 3 session({ 4 secret: 'my-secret', // Secret used to sign session ID cookies 5 resave: false, // Prevent resaving unchanged sessions 6 saveUninitialized: false, // Don't save empty sessions 7 cookie: { 8 secure: false, // Allow cookies over HTTP (use true for HTTPS) 9 sameSite: 'Lax', // Block most cross-site requests, allow top-level 10 }, 11 }), 12 ); 13 14 // Serve static assets such as stylesheets or client-side scripts 15 app.useStaticAssets(join(__dirname, '..', 'public')); 16 17 // Start the application on port 3000 18 await app.listen(3000); 19} 20bootstrap();

In the above code:

  1. Session Middleware:

    • secret: This is a string used to sign and validate the session cookie. You should replace this with a strong secret key in production.
    • resave: false: Sessions are only saved when modified. This reduces unnecessary storage.
    • saveUninitialized: false: New sessions that haven’t been modified (such as those where no data has been set) won’t be saved to the store.
    • cookie:
      • secure: false: Allows cookies to be sent over HTTP. In production, set this to true to ensure cookies are only sent over HTTPS.
      • sameSite: 'Lax': Blocks most cross-site requests, improving security by allowing cookies to be sent only with top-level navigations and same-site requests.
  2. Static Assets: We serve static assets (like CSS, JS, or images) from a public directory. This ensures our web pages are styled and functional.

Creating a Controller to Manage Sessions

Now that we have session management set up, we can use it to track user activity. Let's create a controller that increments a "visit" count each time the user visits a page.

TypeScript
1import { Controller, Get, Session, Res, HttpStatus } from '@nestjs/common'; 2import { Response } from 'express'; 3 4@Controller() 5export class AppController { 6 7 // Route to display the homepage and track the number of visits 8 @Get() 9 trackVisits(@Session() session: Record<string, any>, @Res() res: Response) { 10 // Check if this session has a "visits" count, and increment it 11 session.visits = session.visits ? session.visits + 1 : 1; 12 13 // Return the visit count to the view 14 return res.status(HttpStatus.OK).render('index', { message: `You have visited this page ${session.visits} times.` }); 15 } 16}
  • The @Session() Decorator: The @Session() decorator in NestJS is used to access the session data in a controller method. It is a wrapper around the request session object, which is created and maintained by the session middleware (express-session).

    When a request is made to the server, the session object is attached to the request. This session object holds user-specific information like the userId, or in this case, the visit count. By using @Session(), you can easily access and manipulate session data without needing to manage the underlying session mechanisms directly.

  • Session Tracking:

    • session.visits: This checks whether a session already has a visits count. If it does, it increments the count. If not, it initializes the count at 1.
    • The session data persists across requests, so every time the user revisits this route, the visit count increases.
  • Rendering the View: We use res.status(HttpStatus.OK).render() to render the index view, passing the message (which contains the number of visits) to the template for display.

Configuring the Handlebars View

Finally, we need a simple Handlebars template to display the number of visits:

HTML, XML
1<!-- views/index.hbs --> 2<!DOCTYPE html> 3<html> 4<head> 5 <title>Visit Tracker</title> 6</head> 7<body> 8 <h1>{{message}}</h1> 9</body> 10</html>

This template simply displays the message passed from the controller, which tells the user how many times they have visited the page.

Why Sessions Matter

Session management is critical for many features of a web application:

  • Tracking User Activity: You can track how often a user visits a particular page or what actions they have performed.
  • Storing Data Across Requests: Unlike HTTP, which is stateless, sessions allow you to maintain state (such as login status or cart contents) across multiple requests.
  • Security: Sessions can help manage user authentication and ensure that each request is tied to a specific user without constantly passing sensitive data like credentials.

By implementing session management, you have a fundamental building block for creating more dynamic, interactive, and secure web applications. Understanding how sessions work is essential for building features like user login, personalization, and more.

Ready to Practice?

You’ve just learned how to implement session management in a NestJS app. In the next lesson, we will build on this foundation and implement session-based authentication using Passport.js.

Now it's time to head to the practice section and see how everything works in action! Let's begin!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.