Learn how to manage state between requests in your NestJS application using cookies and sessions, essentials for authentication and user experience personalization.
Getting Started
Cookies are small pieces of data stored on the client-side, which are sent back and forth with each request, thereby enabling session management, tracking, and personalization. Sessions, on the other hand, maintain user data on the server-side, typically identifying the data with a unique session ID stored as a cookie on the client-side. Working with these mechanisms is crucial for stateful interactions in any web application.
Installing necessary packages:
npm install @nestjs/cookies express-session cookie-parser
Using Cookies in NestJS
To use cookies, first, we need to configure the middleware. Import cookieParser
in your main.ts
:
import * as cookieParser from 'cookie-parser';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cookieParser());
// Other middleware
await app.listen(3000);
}
bootstrap();
Setting and reading cookies in controllers is straight forward:
import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';
@Controller('example')
export class ExampleController {
@Get('/set-cookie')
setCookie(@Res() response: Response) {
response.cookie('test', 'Nest Cookie Value', { httpOnly: true });
return 'Cookie set';
}
@Get('/read-cookie')
readCookie(@Req() request: Request) {
const cookie = request.cookies['test'];
return `Read cookie: ${cookie}`;
}
}
Using Sessions in NestJS
Setting Up Sessions
To enable sessions, you need to configure express-session
. First, set it up in the AppModule
‘s imports:
import { Module } from '@nestjs/common';
import * as session from 'express-session';
@Module({
imports: [
// other imports...
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
}),
],
})
export class AppModule {}
Using Session in Controllers
With the setup complete, sessions can be handled in a similar manner as cookies:
import { Controller, Get, Session } from '@nestjs/common';
@Controller('sessions')
export class SessionsController {
@Get('/set')
setSession(@Session() session: Record<string, any>) {
session.visits = (session.visits || 0) + 1;
return session.visits;
}
@Get('/get')
getSession(@Session() session: Record<string, any>) {
return session.visits;
}
}
Security is paramount when dealing with sessions. Make sure to use options like ‘httpOnly’, ‘secure’, ‘sameSite’, etc., when setting cookies and choose a store like Redis or a database for production-level session persistence.
Integrating Session Stores
For production, it’s recommended to use a persistent session store. Here’s how to integrate the popular connect-redis
store:
import * as session from 'express-session';
import * as Redis from 'ioredis';
import * as connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);
const redisClient = new Redis();
@Module({
imports: [
session({
store: new RedisStore({ client: redisClient }),
secret: 'secret',
resave: false,
saveUninitialized: false,
}),
// other imports...
],
})
export class AppModule {}
Advanced Usage: Custom Decorators
For better reusability and abstraction, NestJS allows the creation of custom decorators. Here’s how to create a decorator to access the session more effectively:
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const UserSession = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const request = context.switchToHttp().getRequest();
return request.session;
},
);
And use it in a controller:
import { Controller, Get } from '@nestjs/common';
@Controller('custom')
export class CustomController {
@Get('/session')
getSession(@UserSession() session: Record<string, any>) {
return session;
}
}
Summary
This tutorial covered the basics of managing session and cookie data in NestJS, ensuring security measures with proper configuration for a production-ready application, and enhancing codebase modularity with custom decorators. Personalize your app’s state management and leverage these techniques for various user-specific functionalities.