Role-Based Access Control (RBAC) & JWT Security Architecture
Overview
Learnille implements a multi-tiered security model utilizing JSON Web Tokens (JWT) for stateless session authentication and CASL / NestJS Guards for granular Role-Based Access Control (RBAC).
🔐 1. Authentication & Token Architecture
[ Client Application ] ---> POST /auth/login ---> [ NestJS Auth Controller ]
|
Validate password hash (argon2)
|
v
[ Client Application ] <--- Return Tokens <--- [ Generate Access & Refresh Tokens ]
- Access Token (Header: Bearer <jwt>) - Short-lived (15 mins)
- Refresh Token (HTTP-Only Cookie) - Long-lived (7 days, stored in Redis)
Key Security Properties
- Access Token Expiry: 15 minutes.
- Refresh Token Rotation: Refresh tokens are single-use; issuing a new access token invalidates the previous refresh token in Redis.
- Payload Sanitization: JWT payloads contain non-sensitive identifiers only (
userId,email,role,permissions).
🛡 2. Role Hierarchy & Permission Matrix
| Role | Scope & Allowed Capabilities |
|---|---|
STUDENT | Enrolls in courses, streams purchased content, posts comments, leaves reviews, books consultations, manages own profile. |
INSTRUCTOR | Inherits STUDENT permissions + creates/edits courses, uploads media assets, views student course analytics, manages instructor wallet payouts. |
CONSULTANT | Inherits STUDENT permissions + creates consultation offers, configures availability slots, conducts 1-on-1 sessions, manages consultant wallet payouts. |
ADMIN | System-wide administrative access: quality validation queue approvals/rejection, user account management, platform revenue reports, audit log inspection, payout execution. |
🔒 3. NestJS Guard Implementation Standard
All protected controllers must include JwtAuthGuard and @ApiBearerAuth():
@ApiTags('Consultations')
@Controller('consultations')
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth()
export class ConsultationController {
@Post()
@Roles(Role.CONSULTANT, Role.ADMIN)
create(@CurrentUser() user: User, @Body(new ValidationPipe()) dto: CreateConsultationDto) {
return this.consultationService.create(user, dto);
}
}