Local auth & sessions
Authentication uses email and password with server-side sessions stored in Redis. The flow is the same in both REST and GraphQL variants; only the transport layer differs.
Login flow
Section titled “Login flow”- The client sends
emailandpasswordto the login endpoint. LocalStrategyvalidates the credentials viaAuthenticationService.validateUser.- The service checks that the user exists, the email is verified, and the password matches the Argon2id hash.
- The user’s ID is written to the session.
- Subsequent requests include the session cookie, and
SessionAuthGuardloads the user fromuserId.
Registration flow
Section titled “Registration flow”- The client sends username, email, password, and confirm password.
registerDtovalidates that the password is strong and matches the confirmation.UserService.createUserstores the user through the configured repository.- A 6-digit OTP is generated, stored in Redis under
verification:<email>with a 600-second TTL, and a mail job is queued. - The client must call the verify endpoint with the code before logging in.
Password reset flow
Section titled “Password reset flow”- The client calls
forgot-passwordwith an email. - A UUID token is generated and stored in Redis under
password-reset:<token>with a 600-second TTL. - A password-reset email is queued.
- The client calls
reset-passwordwith the token and a new password. - The token is validated, the new password is hashed, and the user is updated.
Session management
Section titled “Session management”createSessionMiddleware in src/core/authentication/session/session.middleware.ts creates the Express session middleware with connect-redis. The session cookie is shared between REST, GraphQL, and WebSocket connections.
createSessionMiddleware(configService, redisService)Logout calls request.session.destroy(), which removes the session from Redis and clears the cookie.
Guards
Section titled “Guards”LocalGuard— Runs the Passport local strategy on login. Populatesrequest.user.SessionAuthGuard— Readsrequest.session.userId, loads the user, and attaches it torequest.user. Use it on any route that requires authentication.CurrentUserdecorator — Returns the authenticated user fromrequest.user.
GraphQL differences
Section titled “GraphQL differences”In the GraphQL variant, the login mutation bypasses LocalGuard because GraphQL requests do not populate req.body for Passport. The resolver calls AuthenticationService.validateUser directly and then login.
The SessionAuthGuard and CurrentUser decorator detect GraphQL context with GqlExecutionContext so the same guards work for both REST and GraphQL endpoints.
Hashing
Section titled “Hashing”Passwords are hashed with Argon2id using argon2. Compare hashes with the compareHash utility and never store plain text passwords.
Email verification requirement
Section titled “Email verification requirement”validateUser rejects unverified users. This means the login endpoint returns 401 until the email is verified. If you want a different flow, change the check in AuthenticationService.validateUser.