ADR 0007: Hybrid phone OTP login (Twilio SMS + WhatsApp)
Status
Accepted — 2026-06-02
Context
Parents and field staff in Iraq often prefer mobile login without memorizing passwords. The product already stores users.phone and uses Express session cookies. We need passwordless OTP while keeping password login for operators who set credentials explicitly.
Decision
- Hybrid rule: if
users.password_hashis set → login with email or normalized phone + password (no OTP). If no password → phone required; login via 6-digit OTP. - Channels: Twilio SMS (plain body) and optional WhatsApp (Meta-approved Authentication template via Twilio Content API).
- API:
POST /api/auth/login/method,/api/auth/otp/request,/api/auth/otp/verify; extend/api/auth/loginwithidentifier. - Storage:
users.phone_normalized(unique),auth_otp_challenges(hashed code, TTL, attempt limit). - Secrets: GitHub
PRODUCTION_TWILIO_*→ server.envviadeploy/patch-env-github-secrets.sh.
Consequences
- Twilio + Meta Business setup required for production WhatsApp; SMS needs Iraq geo permissions.
- Operators must assign phone for OTP-only accounts; duplicate phones blocked by unique index.
- Future Keycloak migration should preserve the same client contract (
identifier+ method discovery).
References
lib/phoneNormalize.ts,lib/smsOtp.ts,server.ts.github/DEPLOY-SECRETS.md(Twilio OTP section)