- Added account types and privileged account types constants. - Created admin user controller for updating user security fields. - Developed role assignment controller for managing user roles. - Implemented validation middleware for request schemas. - Defined user role and auth session models for database interactions. - Created services for authentication, email notifications, and OTP handling. - Developed OAuth service for Google and Apple authentication. - Added JWT utility functions for token generation and verification. - Implemented comprehensive tests for authentication, session management, and password policies. - Created migration for updating user schema and adding new tables for auth sessions and user identities.
5.1 KiB
ZUMRI Authentication API
All endpoints are available under both /api/auth and /api/v1/auth; new clients should use /api/v1. JSON errors use the Phase 0 standard error envelope. Examples contain placeholders only.
Account states
PENDING_VERIFICATION: registration exists but password/OAuth session creation is denied.ACTIVE: authentication and refresh are permitted.SUSPENDEDandDEACTIVATED: login, refresh, and access-token middleware are denied.
Register a customer
POST /api/v1/auth/register
{"firstName":"Asha","lastName":"Perera","email":"asha@example.com","password":"Strong!1234x","phoneNumber":"+94000000000","address":"Customer-provided value"}
Public registration always creates customer; supplied privileged account fields are rejected/stripped by strict validation. Business and privileged registration are not public Phase 1 flows.
Verify or resend email verification
POST /api/v1/auth/verify-email—{"token":"verification-token-from-email"}POST /api/v1/auth/resend-verification—{"email":"asha@example.com"}
Tokens are random, stored only by hash in Redis, expire, and are single-use. Resend invalidates the previous token. Resend returns a generic response.
Password plus OTP login
POST /api/v1/auth/login
{"email":"asha@example.com","password":"Strong!1234x","rememberMe":true,"clientType":"WEB","deviceName":"Personal laptop"}
Successful credential verification returns HTTP 202 and a challengeId; it does not create a session. A hashed six-digit OTP challenge is stored in Redis for the configured TTL and attempt limit.
POST /api/v1/auth/verify-otp
{"challengeId":"00000000-0000-4000-8000-000000000000","otp":"000000","clientType":"WEB"}
Successful verification consumes the challenge, creates a durable session, and issues tokens. POST /api/v1/auth/req-otp remains an alias for login challenge creation. The historical endpoint that submitted email+OTP to /login is intentionally superseded by challenge IDs.
Token transport
clientType: WEB sets access_token and refresh_token as HttpOnly cookies. Production cookies use Secure and SameSite=None for the intended cross-subdomain frontend/API deployment. The refresh cookie is restricted to /api. The response includes the access token for current compatibility but never includes the web refresh token.
clientType: MOBILE returns access and refresh tokens in JSON and does not depend on cookies. Mobile clients must store the refresh token in operating-system secure storage. Access tokens remain short-lived regardless of Remember Me.
Refresh and rotation
POST /api/v1/auth/refresh
Web request body may be {}; mobile sends {"clientType":"MOBILE","refreshToken":"opaque-token"}. Every successful call revokes/replaces the previous session row and returns a new token pair. Replaying a rotated token revokes its entire token family. Only SHA-256 refresh hashes are persisted.
Current identity
GET /api/v1/auth/me requires the access cookie or Authorization: Bearer <access-token>. It returns identity fields, account state, verification status, profile, and effective permissions. It omits password, token version, session hashes, and OAuth internals.
Logout
POST /api/v1/auth/logoutrevokes the session identified by refresh or access token and is idempotent.POST /api/v1/auth/logout-allrequires authentication, incrementstokenVersion, revokes every active session, and clears cookies.
Password recovery and change
POST /api/v1/auth/forgot-password—{"email":"asha@example.com"}; response is generic.POST /api/v1/auth/reset-password— token,newPassword,confirmPassword.POST /api/v1/auth/change-password— authenticated;currentPassword,newPassword,confirmPassword.
Reset tokens are random, hash-only Redis records and atomically consumed. Reset/change enforce the same password policy, increment token version, and revoke all sessions. The user must log in again.
Google and Apple
POST /api/v1/auth/googlePOST /api/v1/auth/apple
{"idToken":"provider-signed-id-token","rememberMe":false,"clientType":"WEB"}
Google verification validates signature/audience/issuer/expiry through Google's verifier and requires verified email. Apple validates the provider JWKS signature, issuer, audience, expiry, and stable subject. Identities persist (provider, provider_subject) uniquely; provider tokens are discarded. Verified email auto-linking is permitted only for customer accounts. Privileged and rider accounts are never automatically linked by email.
Administrative and rider compatibility
POST /api/v1/admin/auth/loginand/verify-otpuse the shared challenge/session flow but only accept privileged account types.POST /api/v1/rider/auth/loginand/verify-otpuse the same system and only accept rider accounts.
No separate token implementation exists for these actors.
Password policy
Minimum 12 characters with uppercase, lowercase, a symbol, and at least four numeric characters. Registration, reset, and change use the same Zod schema.