Skip to content

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

RoleScope & Allowed Capabilities
STUDENTEnrolls in courses, streams purchased content, posts comments, leaves reviews, books consultations, manages own profile.
INSTRUCTORInherits STUDENT permissions + creates/edits courses, uploads media assets, views student course analytics, manages instructor wallet payouts.
CONSULTANTInherits STUDENT permissions + creates consultation offers, configures availability slots, conducts 1-on-1 sessions, manages consultant wallet payouts.
ADMINSystem-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);
}
}