Authentication Decorators¶
Overview¶
The Authentication module provides custom decorators that simplify route protection and role-based access control in the BidScript backend. These decorators work with guards to provide a clean and declarative way to secure endpoints.
Public Decorator¶
Overview¶
The @Public() decorator marks routes as publicly accessible, exempting them from the global JWT authentication guard.
Source: src/auth/decorators/public.decorator.ts¶
import { SetMetadata } from '@nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
Usage¶
import { Public } from './auth/decorators/public.decorator';
@Controller('auth')
export class AuthController {
@Public()
@Post('login')
login(@Body() loginDto: LoginDto) {
// This endpoint can be accessed without authentication
}
@Get('profile')
getProfile(@Request() req) {
// This endpoint requires authentication
}
}
How It Works¶
- The decorator uses NestJS's
SetMetadatafunction to attach metadata to the route - The
JwtAuthGuardchecks for this metadata using theReflectorservice - If the metadata is present and set to
true, the guard allows the request without JWT validation
Roles Decorator¶
Overview¶
The @Roles() decorator specifies which user roles are allowed to access a particular route. It works in conjunction with the RolesGuard.
Source: src/auth/decorators/roles.decorator.ts¶
import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
Usage¶
import { Roles } from './auth/decorators/roles.decorator';
import { RolesGuard } from './auth/guards/roles.guard';
@Controller('admin')
export class AdminController {
@Roles('admin')
@UseGuards(RolesGuard)
@Get('dashboard')
adminDashboard() {
// Only users with the 'admin' role can access this endpoint
}
@Roles('admin', 'supervisor')
@UseGuards(RolesGuard)
@Get('reports')
reports() {
// Users with either 'admin' or 'supervisor' roles can access this endpoint
}
}
How It Works¶
- The decorator accepts one or more role strings as arguments
- It uses
SetMetadatato attach these roles to the route as metadata - The
RolesGuardextracts this metadata and compares it with the user's roles - The guard allows the request only if the user has at least one of the required roles
Current User Decorator¶
Overview¶
The @CurrentUser() decorator provides a convenient way to access the authenticated user from the request object.
Source: src/auth/decorators/current-user.decorator.ts¶
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
Usage¶
import { CurrentUser } from './auth/decorators/current-user.decorator';
import { User } from './types/interfaces/user.interface';
@Controller('user')
export class UserController {
@Get('profile')
getProfile(@CurrentUser() user: User) {
// The user object is automatically extracted from the request
return user;
}
@Post('update-preferences')
updatePreferences(
@CurrentUser() user: User,
@Body() preferencesDto: PreferencesDto,
) {
// Use the user ID from the authenticated user
return this.userService.updatePreferences(user.id, preferencesDto);
}
}
How It Works¶
- The decorator is created using NestJS's
createParamDecoratorfunction - When the route is executed, the decorator extracts the user object from the request
- The user object was previously attached to the request by the JWT authentication strategy
- The extracted user is provided as a parameter to the route handler
Combining Decorators¶
These decorators can be combined to create sophisticated access control rules:
@Controller('documents')
export class DocumentController {
@Public()
@Get('public')
getPublicDocuments() {
// Accessible without authentication
}
@Get('user')
getUserDocuments(@CurrentUser() user: User) {
// Requires authentication, no specific roles
}
@Roles('editor', 'admin')
@UseGuards(RolesGuard)
@Post('create')
createDocument(@CurrentUser() user: User, @Body() documentDto: DocumentDto) {
// Requires authentication and specific roles
}
}
Error Handling¶
When decorators are used with guards, they participate in the authentication and authorization flow:
- Missing or invalid JWT token:
401 Unauthorized - Missing required roles:
403 Forbidden
Best Practices¶
- Use
@Public()sparingly, only for endpoints that must be accessible without authentication - Always combine
@Roles()with@UseGuards(RolesGuard)to enforce role checks - Use
@CurrentUser()instead of manually extracting the user from the request object