- 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.
8.9 KiB
ZUMRI Phase 1 Identity and Authorization
Objective
Complete the identity security boundary without beginning commerce modules: verified registration, password+OTP authentication, durable revocable sessions, social identity verification, account-state enforcement, repaired configurable RBAC, and ownership-safe self service.
Existing Components Reused
User/Profile and customer-extension models, Sequelize registration, Redis client, bcrypt helper, email templates/transport, hashed verification/reset concepts, activity queue, permission/role/grant models, permission cache, Phase 0 error/rate-limit/request-ID middleware, dual API mounting, tests, and migrations were extended rather than replaced.
Identity Model
User is the account and contains broad accountType, state, password hash (nullable for social-only customers), verification/password timestamps, tokenVersion, and lastLoginAt. UserIdentity maps Google/Apple stable subjects to User. AuthSession persists refresh credentials/device context and rotation state. UserRole assigns configurable Roles independently from account type.
Account Types
Canonical application constants map to persisted lowercase values: SUPER_ADMIN=superadmin, ADMIN=admin, MANAGER=manager, CUSTOMER=customer, BUSINESS_CUSTOMER=business_customer, RIDER=rider, SUPPORT_AGENT=support_agent. Existing lowercase values remain valid.
Role vs Account Type
Account type is a broad trusted identity category used for hard security boundaries. Role is configurable authorization grouping. Users may have multiple roles through UserRole; effective permissions are the union of role grants and direct additive UserPermission grants. This removes dependence on undeclared User.roleID.
Session Architecture
Password -> OTP Challenge -> Verify OTP -> AuthSession
-> Access JWT + opaque Refresh Token
-> transactional rotation -> logout/revocation
Sessions support multiple devices, user-agent/IP/device metadata, Remember Me, token families, last use, expiry, revocation reason, and replacement linkage. Raw refresh tokens exist only at issuance/transport.
Access Token
HS256 JWTs are short-lived and contain sub, sid, and tokenVersion, plus iss, aud, iat, and exp. Middleware enforces algorithm, signature, issuer, audience, expiry, live User state/token version, and live non-revoked session state. It loads permissions server-side rather than embedding them.
Refresh Token Rotation
Refresh tokens are opaque session-id.random-secret values. The database stores only SHA-256 hashes. Rotation locks the current session row and User in a transaction, creates a same-family replacement, and revokes/links the old row.
Reuse Detection
Presentation of a revoked/replaced or hash-mismatched known session token revokes all active members of that token family and returns the same invalid-session boundary. Row locks ensure two concurrent refresh calls cannot both succeed.
Remember Me
Remember Me changes only refresh-session lifetime: REFRESH_TOKEN_TTL_DAYS versus REMEMBER_ME_REFRESH_TOKEN_TTL_DAYS. Access lifetime remains ACCESS_TOKEN_TTL.
Account Status Enforcement
Only ACTIVE can finish login, refresh, or use protected endpoints. Pending, suspended, and deactivated accounts are rejected using current database state, not stale claims. Password/security administration increments token version and revokes sessions.
Password Policy
One Zod policy requires at least 12 characters, uppercase, lowercase, a symbol, and four digits. It is used by registration, reset, and change-password flows. Reset/change require confirmation and reject reuse of the current password.
Email Verification
Verification tokens are cryptographically random and hash-only in Redis. They expire, are consumed atomically, and activate the account. Per-user pointers let resend invalidate an earlier token. Resend responses are generic and rate limited.
Password Recovery
Forgot-password normalizes/validates email and returns a generic response. Reset tokens are random, stored hashed with TTL, atomically consumed using Redis GETDEL, and never logged. Successful reset updates the hash/timestamp/tokenVersion and revokes every session.
Google Authentication
The backend verifies Google ID tokens against configured audience and uses Google's sub; verified email is required. Provider access tokens are not stored. Automated tests mock Google's verifier.
Apple Authentication
The backend obtains/caches Apple's JWKS, selects the signed key, and verifies RS256 signature, Apple issuer, configured audience, expiry, and sub. First-login email is used only when verified. Tests use a locally signed RSA token and mocked JWKS response.
OAuth Account Linking Rules
Existing provider subject wins. Otherwise a strongly verified provider email may link/create a customer. Email-only automatic linking is denied for super admins, admins, managers, support agents, and riders. Provider subject is unique and provider tokens/secrets are not persisted. Manual privileged linking remains deferred.
Role and Permission Architecture
/api/v1/permissions is now mounted and default-denied to SUPER_ADMIN at router level. Existing CRUD is retained behind that boundary. Role names and role/user grant pairs have unique constraints. UserRole pairs are unique. Model hooks and assignment controllers invalidate affected permission caches.
Ownership Authorization
GET/PATCH /user/me provides self service. Self update allowlists only first and last name; account type/status/roles/security fields are rejected. ID-based legacy mutation is restricted to SUPER_ADMIN, and no arbitrary ID read route is exposed. Profile image access uses reusable self-or-admin ownership middleware.
New Database Tables
auth_sessionsuser_identitiesuser_roles
User adds tokenVersion and lastLoginAt; password becomes nullable for verified social-only users; the account-type ENUM expands to all canonical types.
New Migrations
20260903010000-phase-1-identity-security.js is forward-only relative to the Phase 0 baseline and was not executed. Before applying to an existing database, diagnose duplicate roles.roleName, (role_id,permission_id), and (user_id,permission_id) rows because unique indexes intentionally fail on dirty data. Back up and test a restored database first.
API Endpoints
Auth: register, login challenge, verify OTP, refresh, logout, logout-all, forgot/reset/change password, verify/resend email, Google, Apple, and me. Thin shared-flow admin and rider login routes exist. Admin User status/account-type endpoints and protected permission/UserRole endpoints are mounted. See Documentation/API_AUTHENTICATION.md.
Security Controls
Hash-only OTP/reset/verification/refresh persistence; cryptographic random generation; bounded OTP attempts; single-use challenges; short access TTL; durable revocation; replay-family revocation; DB row locks; account-state/token-version checks; strict Zod bodies; generic enumeration responses; provider signature/audience checks; customer-only public registration; field allowlists; ownership checks; and no token/OTP credential logging.
Tests
Unit coverage includes password policy, JWT claims/wrong issuer-audience/expiry/malformed input, OTP format/hash-only persistence/failure states, refresh hash-only persistence/rotation/replay, account-status/password-login behavior, and Google/Apple verification. Integration coverage preserves Phase 0 health/error behavior and checks RBAC denial, self mass-assignment, other-user mutation, suspended access, and Bull Board admin access. External DB/Redis/email/OAuth services are mocked.
Legacy Compatibility
Both /api and /api/v1 remain. /auth/req-otp aliases new login challenge creation; /profile password endpoints delegate to the same hardened controllers. The old email+OTP /auth/login second step is intentionally replaced by /verify-otp with challenge IDs because the old email-keyed flow could not meet security requirements.
Remaining Known Issues
Manual privileged OAuth linking and secure email-change confirmation are deferred. Full email queue/delivery tracking remains Phase 2 infrastructure work. Existing business registration/account approval is not part of this phase. Role/grant uniqueness migration requires deployed-data diagnostics. The baseline test suite mocks MySQL/Redis; staging integration tests must run after migration review. Existing non-auth legacy routes may still contain account-name/ownership debt outside Phase 1 scope.
Phase 2 Prerequisites
Review and run both migrations on a restored environment, configure mail plus Google/Apple client audiences where those flows are enabled, run staging MySQL/Redis integration tests, and seed the initial SUPER_ADMIN/roles/permissions through a controlled operational process. Once complete, identity is ready for the next non-commerce phase requested by the development roadmap.