Role-Based Access Control (RBAC) & JWT Security Architecture
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); }}