Problem
auth.guard.ts canActivate() fires a userRepository.findOne() on every authenticated request to read the user's role. This adds a DB roundtrip to every API call, even read-only endpoints.
crime-reports.gateway.ts already reads payload.role directly from the JWT (line ~40) — the guard is inconsistent with its own codebase.
Proposed Solution — Embed role in JWT payload
What changes
auth.service.ts — generateUserTokens():
// Before
jwtService.sign({ userId: user.id })
// After
jwtService.sign({ userId: user.id, role: user.role })
auth.guard.ts — canActivate():
- Remove
@InjectRepository(User) injection
- Remove
userRepository.findOne() call
- Read role from
payload.role (already decoded from JWT)
Security note
Role changes take up to 1 × access token TTL (typically 1h) to propagate — this is acceptable. If a user is deleted or demoted urgently, invalidate their refresh token to block re-authentication.
Files to modify
| File |
Action |
src/auth/auth.service.ts |
Add role: user.role to jwtService.sign() call |
src/auth/guards/auth.guard.ts |
Remove @InjectRepository(User), remove findOne(), read payload.role |
Benefits
- Eliminates 1 DB query per authenticated request
- Consistent with gateway's existing approach
AuthGuard no longer depends on TypeOrmModule — cleaner module graph
References
Architecture RFC session — 2026-04-12
Problem
auth.guard.tscanActivate()fires auserRepository.findOne()on every authenticated request to read the user's role. This adds a DB roundtrip to every API call, even read-only endpoints.crime-reports.gateway.tsalready readspayload.roledirectly from the JWT (line ~40) — the guard is inconsistent with its own codebase.Proposed Solution — Embed role in JWT payload
What changes
auth.service.ts—generateUserTokens():auth.guard.ts—canActivate():@InjectRepository(User)injectionuserRepository.findOne()callpayload.role(already decoded from JWT)Security note
Role changes take up to 1 × access token TTL (typically 1h) to propagate — this is acceptable. If a user is deleted or demoted urgently, invalidate their refresh token to block re-authentication.
Files to modify
src/auth/auth.service.tsrole: user.roleto jwtService.sign() callsrc/auth/guards/auth.guard.ts@InjectRepository(User), removefindOne(), readpayload.roleBenefits
AuthGuardno longer depends onTypeOrmModule— cleaner module graphReferences
Architecture RFC session — 2026-04-12