Secure your app using JWT-based authentication and granular role-based access control.
Welcome to the world of JWT Authentication! In this chapter, you'll learn how to implement secure login and signup flows using Passport
and NestJS AuthModule
. We'll cover everything from token management to protecting routes with guards.
JWT (JSON Web Tokens) are a compact, URL-safe means of representing claims to be transferred between parties in JSON format. They're widely used for authentication and information exchange.
@nestjs/passport
, passport-jwt
, and dotenv
.import { Module } from '@nestjs/common';
import { AuthModule as NestAuthModule } from '@nestjs/auth';
@Module({
imports: [NestAuthModule.forRoot({
secret: 'your-secret-key',
signOptions: { expiresIn: '1d' }
})],
})
export class AuthModule {};
NestJS uses the strategy pattern to handle different authentication mechanisms. Each strategy is a class that implements a common interface.
import { Strategy } from 'passport-jwt';
export const jwtStrategy = new Strategy(
{
secret: 'your-secret-key',
passReqToCallback: false,
},
async (payload, done) => {
// Validate and return user
done(null, payload);
}
);
Guards are a core feature of NestJS that allow you to control access to your application's endpoints. They can be used to check if a user is authenticated before allowing access to a route.
import { CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
export class AuthGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const isPublic = this.reflector.get('isPublic', context.getHandler());
return !isPublic;
}
}
Welcome to our comprehensive guide on Role-based Access Control (RBAC) and Guards in NestJS! In this chapter, we'll explore how to build robust access control systems using custom decorators, metadata reflection, and guards. You'll learn how to implement both role-based and permission-based patterns to protect sensitive endpoints while maintaining dynamic scoping based on authenticated users.
Before diving into implementation, let's understand the core concepts of RBAC:
Guards are middleware-like functions that intercept incoming requests and determine if access should be granted or denied.
import { CanActivate, ExecutionContext } from '@nestjs/common';
export class RoleGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
// Example logic: Check if user has required role
const userRoles = request.user.roles;
return userRoles.includes('admin');
}
}
NestJS allows us to create custom decorators using metadata reflection. This enables us to define roles and permissions directly on our controller methods.
@UseGuards(RoleGuard)
@SetMetadata('roles', ['admin'])
export class UserController {
@Get()
findAll(@CurrentUser() user: User) {
return user;
}
}
Scoping allows you to dynamically control access based on context-specific data, such as ownership or project membership.
@UseGuards(OwnershipGuard)
export class PostController {
@Get(':id')
findOne(@Param('id') id: string, @CurrentUser() user: User) {
return this.postsService.findOne(id);
}
}
// OwnershipGuard implementation
if (!post.ownerId.equals(user.id)) {
throw new ForbiddenException('You are not the owner');
}
Let's outline steps to build a production-ready RBAC system:
Common issues and how to resolve them:
Question 1 of 11