Auth Module Backend Documentation
Internal auth architecture with split admin/customer controllers for login, sessions, password reset, and verification.
Auth - Backend Documentation
1. Module Scope
Shared AuthModule provides auth primitives used by two HTTP surfaces:
- Admin controller:
/api/auth/* - Mobile customer controller:
/api/mobile/auth/*
Core responsibilities:
- email/password auth
- session/token issuance + refresh/logout
- email/phone verification flows
- password reset flows
Accounts are provisioned by an administrator through the Users and Team modules. There is no self-service registration and no self-service account deletion.
2. Composition
2.1 Controllers
Admin / backoffice, under apps/api/src/modules/auth/:
auth-session.controller.ts,auth-password.controller.ts,auth-verification.controller.ts
Customer / mobile, under apps/api/src/modules/mobile/auth/:
auth-session,auth-password,auth-verificationcontrollers
2.2 Strategies and guards
LocalStrategy+LocalAuthGuardfor admin email loginJwtStrategy+JwtAuthGuardfor protected routes
2.3 Core services
AuthService— thin facade; delegates to the collaborators belowAuthPasswordService— password reset/set flowsAuthLoginService— credential validation and loginAuthSessionService,AuthUserQueryService,AuthTokenService,AuthEmailService,VerificationTokenService— the last of these mints, redeems, and retires the emailed verification records described in §3.2, and is consumed by the People module as well as by auth's own routes
3. Behavior Clarifications
3.1 Banned accounts
banned is the only account-level control. A banned account cannot authenticate.
3.2 Account-entry purposes
VerificationTokenService mints one row per emailed credential, keyed by
(identifier, purpose). Two of the verification_purpose values grant entry to
an account by link:
VerificationTokenService.ACCOUNT_ENTRY_PURPOSES = ["password_reset", "account_invite"]
password_reset— forgot-password, and the administrator-issued reset link fromPeopleAccountService.sendPasswordResetLink. Expires afterOTP_EXPIRY_MINUTES, 15 minutes by default.account_invite— minted byPeopleAccountServicewhen an administrator grants somebody sign-in access. It passesexpiresInMs: ACCOUNT_INVITE_TTL_MS, seven days, because a token that dies before the recipient next opens their inbox is not an invitation.
AuthPasswordService.resetPassword resolves the token branch through
consumeByToken(ACCOUNT_ENTRY_PURPOSES, token). Widening the purpose there is
safe because the predicate still selects on the token hash, which identifies
exactly one row; the purpose list only widens which rows are eligible.
consumeByOtp stays scoped to password_reset for the inverse reason. It selects
on (purpose, identifier) with limit(1) and no ordering, so a purpose list
would return an arbitrary row when somebody holds both an invitation and a reset.
A wrong row means a correct code fails to match, incrementAttempts fires against
it, and five of those retire the record. An invitation therefore redeems by link
only — its OTP is minted, because the factory always mints one, but it is never
rendered into the email and this predicate can never select it.
consumeAccountEntry(recordId, userId, executor?) marks the redeemed record
consumed and deletes every other account-entry record for the same person.
clearExisting is keyed on (identifier, purpose), so an invitation and a reset
coexist as two independently live single-use credentials; choosing one has to
retire the other, or the older link keeps working after a password has already
been set through the newer one.
Both statements run in one transaction. They are the same act: run separately, a failure between them leaves the sibling live — precisely the credential this method exists to retire, now with the password already changed. The executor is threaded so a caller that already owns a transaction keeps ownership of it.
4. Security and Operational Controls
- DTO validation via global
ValidationPipe - endpoint throttling via
IpThrottlerGuard+@IpThrottle - banned-user protection via user-query checks
- token/session rotation centralized in session service
See Auth API Reference for exact routes and request/response shapes.