Architecture
Configuration (src/lib/auth.ts)
The Auth.js configuration lives in src/lib/auth.ts and exports { handlers, auth, signIn, signOut }.
Session Strategy
Custom JWT Claims
Thejwt and session callbacks propagate three pension-specific fields from the user record into every token and session:
Password Hashing
Passwords are hashed with bcryptjs before storage. On authentication,bcrypt.compare() is used — timing-safe by design. Plaintext passwords are never logged, stored, or transmitted.
Login Page
Auth.js is configured to redirect unauthenticated requests to/auth/login:
Auth Flow
1
Credential submission
User submits email + password to
POST /api/auth/signin (handled by Auth.js route handler at src/app/api/auth/[...nextauth]/route.ts).2
Database lookup
Drizzle ORM queries the
users table by email. If DATABASE_URL is not set, the request fails in production.3
Password verification
bcrypt.compare(providedPassword, storedHash) — returns false if the hash does not match. Wrong passwords do not fall through to any fallback.4
JWT issuance
On success, Auth.js issues a signed JWT containing
id, role, brokerId, and employerId. The JWT secret is AUTH_SECRET (required environment variable).5
Session cookie
The JWT is stored in an HttpOnly, Secure, SameSite=Lax cookie. It is not accessible to JavaScript.
Role Mapping
The database schema uses granular role names; Auth.js maps these to application-levelUserRole values:
Development vs Production
In production:DATABASE_URLmust be set — the DB fallback is the only auth pathAUTH_SECRETmust be a cryptographically random string (minimum 32 bytes)- The dev credential fallback returns
nullimmediately
Environment Variables
TypeScript Augmentation
Custom session fields are typed via module augmentation insrc/lib/auth-types.ts, ensuring TypeScript catches any access to undefined session properties at compile time.