Skip to content

JWT Authentication, Multi-Layer RBAC & Coding Conventions (CLAUDE.md) ​

Tài liệu này mô tả chi tiết cơ chế Authentication & Authorization (AuthN/AuthZ) trong apps/backend và tổng hợp các coding conventions bắt buộc của dự án.


1. Dual-Token JWT Authentication & Instant Revocation (token_version) ​

1.1. Login Flow & Subscription Service Gate (enforceServiceGate — TXNG-F46) ​

Khi người dùng gọi POST /api/v1/auth/login (apps/backend/src/modules/auth/auth.service.ts):

  1. Verify Credentials: Kiểm tra email, deleted_at == null, is_active == true và đối chiếu password bằng bcrypt.compare().
  2. Subscription Service Gate (enforceServiceGate): Nếu người dùng thuộc khối Enterprise (role === ROLE.BUSINESS hoặc user_type === 'ENTERPRISE'), hệ thống kiểm tra trạng thái subscription (company.subscription) theo quy tắc TXNG-F46:
    • PENDING: Chặn login (ACCOUNT_NOT_ACTIVATED).
    • TERMINATED hoặc SUSPENDED: Chặn login (SERVICE_TERMINATED / SERVICE_LOCKED).
    • EXPIRED (hoặc ACTIVE nhưng đã quá end_date + grace_days): Tự động chuyển trạng thái gói sang EXPIRED và chặn login (SERVICE_EXPIRED).
  3. Issue Dual Tokens (Access Token 24h + Refresh Token 7d):
    • Access Token (JWT, TTL 24h) chứa payload: { userId, email, role, company_id, token_version }.
    • Refresh Token (JWT ký bằng JWT_REFRESH_SECRET riêng, TTL 7d) chứa { userId, token_version, type: 'refresh' }.
    • Set đồng thời vào HttpOnly Cookie (token, refresh_token, sameSite: 'lax') và trả về trong JSON body để tương thích cả SSR lẫn SPA.

1.2. Instant Token Revocation qua token_version & Redis Cache ​

Trong JwtStrategy.validate() (apps/backend/src/modules/auth/jwt.strategy.ts):

  • Hệ thống cache thông tin permissions của user trong Redis với key user_perms:${userId} (TTL 60 giây).
  • Ở mỗi request, JwtStrategy so sánh payload.token_version trong JWT với cached.tokenVersion (hoặc dbUser.token_version trong PostgreSQL).
  • Khi user logout, resetPassword, hoặc bị Admin khóa tài khoản, hệ thống tăng token_version: { increment: 1 } trong bảng users và xóa key user_perms:${userId} khỏi Redis. Toàn bộ JWT cũ lập tức bị từ chối với mã 401 Unauthorized mà không cần chờ hết hạn 24 giờ.

2. Multi-Layer RBAC & Guard Pipeline ​

apps/backend áp dụng pipeline kiểm soát truy cập nhiều lớp (Defense-in-Depth):

Rendering diagram...

2.1. Permission Aggregation trong JwtStrategy ​

  1. Source 1 (userRolePermissions — Direct/Legacy): Gắn trực tiếp qua bảng trung gian giữa User và Role.
  2. Source 2 (role_assignments — Multi-Role & Scoped RBAC): Cho phép một user nắm giữ nhiều roles (PLATFORM_ADMIN, GOV_ADMIN, GOV_INSPECTOR, ENT_OWNER, ENT_ADMIN, ENT_STAFF...) kèm data scope (unit_ids, industry_codes, company_ids).
  3. Default Permissions (ROLE_DEFAULT_PERMISSIONS): Được merge dựa trên role và organization_types của tenant (ví dụ tenant loại SCHOOL / CATERING tự động nhận bộ quyền cơ bản của phân hệ Bếp ăn học đường).

2.2. Guard Matrix trong apps/backend/src/common/guards/ ​

Guard NameFile PathCore Validation Logic
JwtAuthGuardmodules/auth/jwt-auth.guard.tsBypass nếu route gắn @Public(). Ngược lại kích hoạt PassportStrategy('jwt') để populate req.user (JwtPayload).
PermissionsGuardcommon/guards/permission.guard.ts1. Gọi checkCompanyServiceAccess để chặn doanh nghiệp hết hạn gói dịch vụ (TXNG-F46).
2. Nếu user có role === ROLE.ADMIN (1) → allow (return true).
3. Đọc metadata @CheckPermissions([...]) và đối chiếu với user.permissions theo toán tử AND (default) hoặc OR (PermissionLogic.OR).
AdminGuardcommon/guards/admin.guard.tsChỉ cho phép tài khoản Platform Admin (user.role === ROLE.ADMIN).
AdminOrActiveCompanyGuardcommon/guards/admin-or-active-company.guard.tsCho phép ROLE.ADMIN hoặc user thuộc doanh nghiệp đang ở trạng thái ACTIVE. (Lưu ý Security: Guard này KHÔNG thay thế cho AdminGuard hay PermissionsGuard — xem chi tiết tại SEC-04).

3. Coding Conventions (CLAUDE.md) ​

Từ hệ thống tài liệu nội bộ (CLAUDE.md, apps/frontend/CLAUDE.md, apps/backend/CLAUDE.md), đội ngũ phát triển tuân thủ các quy chuẩn sau:

3.1. Frontend Conventions (apps/frontend) ​

  • Multi-Brand Config (config/brand.ts): Không bao giờ hardcode chuỗi "GoTrace" hay "HanoiTrace" trong UI; luôn đọc từ brand config (NEXT_PUBLIC_BRAND).
  • Component & UI Pattern:
    • Sử dụng bộ shared components trong components/common/ (TableWrapper, FormModal, StatusBadge, ImportExportButtons) kết hợp HeroUI (@heroui/react).
    • Forms sử dụng react-hook-form kết hợp validation schema zod.
  • API Client & Anti-Crawling:
    • Sử dụng centralized API client gắn sẵn auth token và cặp header x-gotrace-nonce / x-gotrace-signature (lib/anti-crawl.ts) khi gọi các public lookup APIs.

3.2. Backend Conventions (apps/backend) ​

  • Multi-Tenancy Enforcement (CompanyHelper):
    • Với các API CRUD hoặc lấy chi tiết của doanh nghiệp, luôn resolve companyId từ user thông qua companyHelper.getCompanyId(user, query.company_id) (Admin được truyền company_id, còn tài khoản Enterprise luôn bị pin cứng vào user.company_id từ DB).
    • Với các API list/analytics cho phép Admin xem toàn hệ thống khi không filter theo tenant, dùng companyHelper.getOptionalCompanyId(user, query.company_id).
  • IP Normalization (@ClientIp()):
    • Sử dụng decorator @ClientIp() (src/common/decorators/client-ip.decorator.ts) thay cho @Ip() mặc định của NestJS để normalize IPv4-mapped IPv6 (::ffff:203.0.113.9 → 203.0.113.9) ngay tại controller boundary trước khi ghi audit log hoặc check rate-limit.
  • Unified Excel Import / Export (TXNG-F49):
    • Không viết lặp lại logic đọc/ghi Excel trong từng service; khai báo ModuleImportExportConfig (*.excel.config.ts) và delegate cho ModuleImportExportService (exportSample, exportData, import, exportErrors).
  • National Gateway Sync & Async VC Signing:
    • Mọi thay đổi dữ liệu cần đồng bộ quốc gia phải gọi enqueueInTx(tx, ...) của @gotrace/integration-outbox ngay bên trong prisma.$transaction.
    • Mọi sự kiện phát sinh W3C VC phải gọi vcOutbox.enqueueInTx(tx, ...) trong DB transaction và gọi vcOutbox.scheduleIssuance(outboxId) ở bước post-commit (bọc trong try/catch để lỗi Redis không làm fail business transaction đã commit).

Technical Documentation & Security Audit Report — kl-audit v3.0