Why Layered Guards?
A single auth middleware can't express the nuanced access rules real APIs need: verified email, specific roles, and resource ownership all vary by endpoint.
NestJS guards are the right abstraction—they compose cleanly and run in declaration order.
The Guard Stack
A typical protected endpoint uses four guards in sequence: AuthGuard validates JWT, VerifiedGuard checks email verification, RolesGuard checks role membership, and OwnershipGuard verifies resource ownership.
@UseGuards(AuthGuard, VerifiedGuard, RolesGuard, OwnershipGuard)
@Roles(Role.OWNER)
@Patch('projects/:id')
updateProject(@Param('id') id: string, @Body() dto: UpdateProjectDto) {
return this.projectService.update(id, dto);
}Ownership Guard Pattern
OwnershipGuard extracts the resource ID from route params, loads the entity from the database, and compares its ownerId field to the authenticated user's ID. This prevents users from modifying resources they don't own, even if they have the correct role.
