Files
Zumri-Backend/Documentation/API_AUTHENTICATION.md
Sathira Sri Sathara 9d3d431416 feat: implement identity and security features
- 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.
2026-09-03 13:56:18 +05:30

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.
  • SUSPENDED and DEACTIVATED: 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/logout revokes the session identified by refresh or access token and is idempotent.
  • POST /api/v1/auth/logout-all requires authentication, increments tokenVersion, 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/google
  • POST /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/login and /verify-otp use the shared challenge/session flow but only accept privileged account types.
  • POST /api/v1/rider/auth/login and /verify-otp use 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.