Guard that verifies if a request has permission to access a protected endpoint. Uses a Role-Based Access Control (RBAC) system with roles and permissions.
❌ Without Authorization:
- Any authenticated user can access any endpoint
- No fine-grained access control
- Can't restrict admin-only features
✅ With Authorization Guard:
- Permission-based access control
- Users have roles, roles have permissions
- Flexible and scalable authorization
┌─────────────────────────────────────────────────────────────────┐
│ RBAC HIERARCHY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User ───────▶ Roles ───────▶ Permissions │
│ │
│ ┌────────┐ ┌─────────┐ ┌──────────────────┐ │
│ │ John │───▶│ Admin │───▶│ user:create │ │
│ └────────┘ └─────────┘ │ user:delete │ │
│ │ │ role:update │ │
│ │ └──────────────────┘ │
│ ▼ │
│ ┌─────────┐ ┌──────────────────┐ │
│ │ User │───▶│ user:read │ │
│ └─────────┘ │ user:update │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. Check if endpoint requires permission (@Permission) │
│ 2. Extract user ID from JWT (request.user.id) │
│ 3. Fetch user with roles from database │
│ 4. Collect all permissions from user's roles │
│ 5. Check if required permission exists │
│ 6. Allow or deny request │
└─────────────────────────────────────────────────────────────────┘
import { Permission } from '@/utils/decorators'
@Controller('users')
export class UserController {
@Post()
@Permission('user:create') // Only users with this permission
async createUser(@Body() input: CreateUserInput) {
return this.userService.create(input)
}
@Delete(':id')
@Permission('user:delete') // Admin-only operation
async deleteUser(@Param('id') id: string) {
return this.userService.delete(id)
}
}Permissions follow the pattern resource:action:
| Permission | Description |
|---|---|
user:create |
Create users |
user:read |
Read users |
user:update |
Update users |
user:delete |
Delete users |
role:create |
Create roles |
role:update |
Update roles |
If no @Permission() decorator is present, the endpoint is accessible to any authenticated user:
@Get('profile')
// No @Permission - any authenticated user can access
async getProfile() {
return this.userService.getProfile()
}Request
│
▼
┌──────────────────────────┐
│ Has @Permission? │──── No ────▶ ✅ Allow
└──────────────────────────┘
│ Yes
▼
┌──────────────────────────┐
│ Has valid user token? │──── No ────▶ ❌ 401 Unauthorized
└──────────────────────────┘
│ Yes
▼
┌──────────────────────────┐
│ User exists in DB? │──── No ────▶ ❌ 401 Unauthorized
└──────────────────────────┘
│ Yes
▼
┌──────────────────────────┐
│ User has permission? │──── No ────▶ ❌ 403 Forbidden
└──────────────────────────┘
│ Yes
▼
✅ Allow Request
401 Unauthorized - No valid token:
{
"error": {
"code": 401,
"message": ["invalidToken"]
}
}403 Forbidden - No permission:
{
"error": {
"code": 403,
"message": ["You Shall Not Pass"],
"context": "UserController/deleteUser",
"parameters": { "permission": "user:delete" }
}
}| Feature | Description |
|---|---|
| Model | Role-Based Access Control (RBAC) |
| Decorator | @Permission('resource:action') |
| Check | User → Roles → Permissions |
| 401 | Invalid or missing token |
| 403 | Valid token, no permission |
Authorization Guard - Fine-grained access control with RBAC.