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.
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.
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:
Bash1npm 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 withExpress
and is necessary for applying middleware likeexpress-session
.
Once these packages are installed, you're ready to integrate session management into your application.
We start by creating an Express
-based NestJS
application and configuring session middleware. For view rendering, we’ll use Handlebars
. Here’s the setup:
TypeScript1import { 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:
- NestExpressApplication: This allows us to use
Express
middleware like session handling in ourNestJS
app. - Handlebars Setup: We set up
Handlebars
as our view engine, specifying where the views and partials (reusable view fragments) are located. - 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.)
Next, we configure the session middleware using the express-session
package. This middleware will manage session data across user requests.
TypeScript1 // 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:
-
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 totrue
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.
-
Static Assets: We serve static assets (like CSS, JS, or images) from a
public
directory. This ensures our web pages are styled and functional.
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.
TypeScript1import { 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 avisits
count. If it does, it increments the count. If not, it initializes the count at1
.- 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 theindex
view, passing themessage
(which contains the number of visits) to the template for display.
Finally, we need a simple Handlebars
template to display the number of visits:
HTML, XML1<!-- 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.
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.
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!