Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/security-use-guards.md
1---2title: Use Guards for Authentication and Authorization3impact: HIGH4impactDescription: Enforces access control before handlers execute5tags: security, guards, authentication, authorization6---78## Use Guards for Authentication and Authorization910Guards determine whether a request should be handled based on authentication state, roles, permissions, or other conditions. They run after middleware but before pipes and interceptors, making them ideal for access control. Use guards instead of manual checks in controllers.1112**Incorrect (manual auth checks in every handler):**1314```typescript15// Manual auth checks in every handler16@Controller('admin')17export class AdminController {18@Get('users')19async getUsers(@Request() req) {20if (!req.user) {21throw new UnauthorizedException();22}23if (!req.user.roles.includes('admin')) {24throw new ForbiddenException();25}26return this.adminService.getUsers();27}2829@Delete('users/:id')30async deleteUser(@Request() req, @Param('id') id: string) {31if (!req.user) {32throw new UnauthorizedException();33}34if (!req.user.roles.includes('admin')) {35throw new ForbiddenException();36}37return this.adminService.deleteUser(id);38}39}40```4142**Correct (guards with declarative decorators):**4344```typescript45// JWT Auth Guard46@Injectable()47export class JwtAuthGuard implements CanActivate {48constructor(49private jwtService: JwtService,50private reflector: Reflector,51) {}5253async canActivate(context: ExecutionContext): Promise<boolean> {54// Check for @Public() decorator55const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [56context.getHandler(),57context.getClass(),58]);59if (isPublic) return true;6061const request = context.switchToHttp().getRequest();62const token = this.extractToken(request);6364if (!token) {65throw new UnauthorizedException('No token provided');66}6768try {69request.user = await this.jwtService.verifyAsync(token);70return true;71} catch {72throw new UnauthorizedException('Invalid token');73}74}7576private extractToken(request: Request): string | undefined {77const [type, token] = request.headers.authorization?.split(' ') ?? [];78return type === 'Bearer' ? token : undefined;79}80}8182// Roles Guard83@Injectable()84export class RolesGuard implements CanActivate {85constructor(private reflector: Reflector) {}8687canActivate(context: ExecutionContext): boolean {88const requiredRoles = this.reflector.getAllAndOverride<Role[]>('roles', [89context.getHandler(),90context.getClass(),91]);9293if (!requiredRoles) return true;9495const { user } = context.switchToHttp().getRequest();96return requiredRoles.some((role) => user.roles?.includes(role));97}98}99100// Decorators101export const Public = () => SetMetadata('isPublic', true);102export const Roles = (...roles: Role[]) => SetMetadata('roles', roles);103104// Register guards globally105@Module({106providers: [107{ provide: APP_GUARD, useClass: JwtAuthGuard },108{ provide: APP_GUARD, useClass: RolesGuard },109],110})111export class AppModule {}112113// Clean controller114@Controller('admin')115@Roles(Role.Admin) // Applied to all routes116export class AdminController {117@Get('users')118getUsers(): Promise<User[]> {119return this.adminService.getUsers();120}121122@Delete('users/:id')123deleteUser(@Param('id') id: string): Promise<void> {124return this.adminService.deleteUser(id);125}126127@Public() // Override: no auth required128@Get('health')129health() {130return { status: 'ok' };131}132}133```134135Reference: [NestJS Guards](https://docs.nestjs.com/guards)136