import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; import type { AuthenticatedUser } from '../strategies/jwt.strategy'; /** * Role-based access control. Applied globally: any authenticated user * reaching a protected route must hold the ADMIN role unless the route * declares a wider set with @Roles(...). Routes without a JwtAuthGuard * (public endpoints) have no `request.user` and are skipped here — their * openness is decided by the controller's own guards. */ @Injectable() export class RolesGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest<{ user?: AuthenticatedUser; }>(); if (!request.user) { return true; // public route — no JwtAuthGuard in front } const required = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), context.getClass(), ]) ?? ['ADMIN']; if (!required.includes(request.user.role)) { throw new ForbiddenException('Insufficient role'); } return true; } }