Careeroza
Protecting Routes Globally
Secure by Default with @Public
Forgetting @UseGuards(JwtAuthGuard) on one controller leaks data. Safer: make the JWT guard global and mark the few open routes with @Public().
src/auth/public.decorator.ts and src/auth/jwt-auth.guard.ts
import { ExecutionContext, Injectable, SetMetadata } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private readonly reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) return true;
return super.canActivate(context);
}
}src/app.module.ts
@Module({
imports: [AuthModule, UsersModule, ProductsModule, OrdersModule],
providers: [
{ provide: APP_GUARD, useClass: JwtAuthGuard }, // every route needs a token...
{ provide: APP_GUARD, useClass: RolesGuard }, // ...then roles are checked
],
})
export class AppModule {}
// products.controller.ts
// @Public() @Get() findAll() {} // browsing the catalogue is open
// @Roles(Role.Admin) @Post() create() {} // token + admin role