While JWTs are a popular method for authentication in modern APIs, sessions and cookies remain a secure and viable solution — especially in traditional web apps or SSR-based systems. NestJS offers seamless integration with session-based authentication, allowing you to manage user sessions and persist state across HTTP requests.
In this module, you’ll learn how to set up session-based authentication, use cookies securely, and understand the differences between JWTs and sessions in a NestJS context.
Table of Contents
- Introduction to Sessions and Cookies
- When to Use Sessions vs JWT
- Installing Required Packages
- Setting Up Sessions with
express-session
- Using
@nestjs/passport
with Sessions - Accessing Session Data in Controllers
- Using Cookies in NestJS
- Security Considerations: CSRF, HTTPS, HttpOnly
- Conclusion
Introduction to Sessions and Cookies
A session stores user data on the server and associates it with a unique identifier (usually stored in a cookie on the client). This approach allows persistent login and secure server-side state management.
Cookies are small pieces of data sent by the server and stored on the client. They are included in every HTTP request to the same origin, making them ideal for session tracking.
When to Use Sessions vs JWT
Feature | JWT | Sessions & Cookies |
---|---|---|
Stateless | ✅ Yes | ❌ No |
Secure via HttpOnly | ⚠️ Manually configured | ✅ By default |
Suitable for SPAs | ✅ Yes | ⚠️ Less suitable without SSR |
Easy token rotation | ❌ Complex | ✅ Simple |
Backend control | ❌ No (token is client-stored) | ✅ Yes (session stored server-side) |
Installing Required Packages
Install the necessary packages for session management:
bashCopyEditnpm install express-session
npm install @nestjs/passport passport
npm install @types/express-session --save-dev
Setting Up Sessions with express-session
In your main.ts
or app.module.ts
, configure the middleware:
tsCopyEdit// main.ts
import * as session from 'express-session';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(
session({
secret: process.env.SESSION_SECRET || 'keyboard_cat',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
maxAge: 1000 * 60 * 60, // 1 hour
},
}),
);
await app.listen(3000);
}
bootstrap();
The
secret
should be stored in environment variables in production.
Using @nestjs/passport
with Sessions
Enable Passport to serialize and deserialize users:
tsCopyEdit// auth.module.ts
import { PassportModule } from '@nestjs/passport';
@Module({
imports: [PassportModule.register({ session: true })],
...
})
export class AuthModule {}
In your local strategy, enable session support:
tsCopyEdit// local.strategy.ts
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super(); // username/password fields by default
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user; // Automatically attached to req.user
}
}
Implement the serializeUser
and deserializeUser
methods in your auth service or a separate passport file:
tsCopyEdit// main.ts or auth.service.ts
import * as passport from 'passport';
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
// Fetch from DB
const user = { id, name: 'John Doe' }; // Replace with real DB call
done(null, user);
});
Accessing Session Data in Controllers
tsCopyEdit@Get('profile')
@UseGuards(AuthGuard('local'))
getProfile(@Req() req: Request) {
return req.user; // Available from session
}
To manually store or access session data:
tsCopyEdit@Post('login')
login(@Req() req) {
req.session.myCustomValue = 'someData';
return { message: 'Logged in!' };
}
Using Cookies in NestJS
You can also work directly with cookies:
Reading Cookies:
tsCopyEdit@Get('cookies')
getCookies(@Req() req) {
return req.cookies;
}
Setting Cookies:
tsCopyEdit@Post('set-cookie')
setCookie(@Res() res: Response) {
res.cookie('theme', 'dark', {
httpOnly: true,
secure: true,
maxAge: 60000,
});
return res.send('Cookie set');
}
Make sure to enable cookie parser:
bashCopyEditnpm install cookie-parser
tsCopyEdit// main.ts
import * as cookieParser from 'cookie-parser';
app.use(cookieParser());
Security Considerations: CSRF, HTTPS, HttpOnly
- Always use HTTPS in production when working with cookies.
- Enable the HttpOnly and Secure flags on cookies to prevent XSS and ensure transport security.
- Consider implementing CSRF protection if your app uses cookies for session authentication.
Conclusion
Sessions and cookies in NestJS provide a robust and secure way to manage user authentication and server-side state. They’re particularly well-suited for SSR applications, admin panels, and traditional web services. While stateless JWT authentication is ideal for APIs, sessions shine in cases where server control and fine-grained security are essential.