Architecture
1. System Context (C4 L1)
Identity is the trust root — every JWT in the platform is signed by this service. JWKS at
/jw-certsis the public endpoint sister services use to verify signatures.
2. Container View (C4 L2)
3. Component View (C4 L3) — Internal Layering
| Layer | Responsibility |
|---|---|
| Routes | 12 base paths in RestPaths |
| Controllers | Auth gate (JWT / BASIC) + permission |
| Services | Business logic (auth + RBAC + OTP + user mgmt) |
| Repositories | Drizzle queries; identifier-aware lookups |
| Components | Mail / SMS / WebSocket |
| Token service | JWKSIssuerTokenService from @nx/core (ES256 signer) |
4. State Machines
Identity has minimal state-machine surface; most flows are validation chains rather than persistent state machines.
| Entity | States | Notes |
|---|---|---|
User.status | ACTIVATED / DEACTIVATED / LOCKED | guard for sign-in |
UserIdentifier.verified | false → true | verification via OTP/token |
Role.type | SYSTEM / CUSTOM / UNKNOWN | SYSTEM rows immutable |
5. Runtime Scenarios
5.1 Sign-in (BASIC scheme)
5.2 Sign-up
5.3 Email OTP — Verify Email Flow
5.4 JWKS Verification by Sister Service
6. Crosscutting Concerns
| Concern | How this service handles it |
|---|---|
| Token signing | ES256 via JWKSIssuerTokenService (from @nx/core); private key from environment / secure config |
| Token verification | NOT done here — sister services pull JWKS over HTTP and verify locally |
| Password storage | Bun.password hashing (argon2-style, internal default) |
| OTP storage | Redis with TTL — hashed code + attempt counter + cooldown + daily quota |
| i18n | Mail/SMS templates in EN + VI; user locale selects on send |
| Logging | IGNIS structured (key: %s); request-id propagated |
| AuthZ | Casbin + PolicyDefinition edges; permissions cached in Redis |
| Soft-delete | SoftDeletableRepository — deletedAt; identifier uniqueness scoped to deletedAt IS NULL |
| IDs | Snowflake via IdGenerator, worker 1 |