ADR-026: Customer authentication — Cognito, mobile-first, passwordless¶
| Status | Accepted |
| Date | 2026-04-10 |
| Deciders | CTO, Chief Risk Officer, Chief Compliance Officer |
| Affects repos | bank-kyc, bank-app |
Context¶
The bank requires a customer authentication architecture that satisfies three constraints simultaneously: regulatory compliance (RBNZ, APRA, and conduct obligations), strong security, and a customer experience that matches or exceeds neobank peers. Traditional username/password authentication is the weakest pattern in use — it is the primary attack surface for account takeover and creates friction that drives abandonment.
The customer interface at launch is mobile-only (iOS and Android). Web-based customer access is not in scope at launch. This constraint enables a cleaner, device-bound authentication model.
Decision¶
AWS Cognito User Pool (customer pool). Mobile-only. Passwordless from day one. Passkey/biometric-bound authentication after onboarding.
Auth flow¶
| Step | What happens |
|---|---|
| Onboarding | Customer enters mobile number → SMS OTP verifies device ownership → KYC/eIDV completes (MOD-009) → email address captured → passkey registered on device (Face ID / Touch ID) |
| Login | Biometric prompt → device passkey challenge → Cognito JWT issued |
| Step-up | Second biometric prompt required for: payments above threshold, changes to account details, adding payees. SMS OTP added for high-value transactions |
| No password | No password is ever created, stored, or transmitted. No password reset flow exists |
Implementation¶
- Cognito custom authentication Lambda triggers implement the OTP verification and passkey challenge flow
- WebAuthn/passkey registration occurs during onboarding and is bound to the device
- Cognito issues short-lived JWTs; refresh tokens are stored in the device's secure enclave
- JWT claims carry customer ID, device ID, and authenticated level — API Gateway validates on every request
Account recovery¶
Email is captured and verified during onboarding (KYC step). The specific recovery flow — whether email magic link, contact centre with liveness check, or a combination — is defined as part of the KYC detailed design. The recovery process will be documented, auditable, and consistent with CCCFA (NZ) and NCCP Act (AU) obligations for customer identification. No recovery path bypasses identity verification.
Mobile-only rationale¶
The customer application at launch is iOS and Android only. This is recorded as the scope of this ADR. If web customer access is added in a future phase, a supplementary ADR will address browser-based passkey UX and session management for that surface.
Consequences¶
Positive: - No password eliminates the primary account takeover attack surface (credential stuffing, phishing, reuse) - Device-bound passkeys cannot be phished — the credential never leaves the device - Biometric authentication matches the neobank peer standard (Monzo, Up Bank, Revolut) - Cognito is AWS-native — customer identity data stays within the ap-southeast-2 boundary; no additional vendor - Cognito free tier covers 50,000 MAUs — significant headroom before authentication cost becomes material - Step-up authentication on high-value actions satisfies RBNZ and APRA strong authentication expectations
Negative: - Device loss requires account recovery — the recovery process adds support overhead and must be clearly designed (see KYC detailed design) - Passkey support requires iOS 16+ and Android 9+ — devices older than this cannot use the app - Cognito custom auth flows are complex to implement and test; Lambda trigger errors must not lock customers out
Alternatives considered¶
Traditional username/password with MFA: Rejected. Passwords are the weakest link; this ADR specifically eliminates them. MFA on top of passwords is inferior to passwordless from a security and UX standpoint.
Auth0 / Okta: Rejected. Additional vendor outside AWS; customer identity data would leave the ap-southeast-2 boundary. Comparable features available via Cognito at lower cost and within the existing cloud boundary.
Supabase Auth: Rejected. Overlaps with Neon Postgres decision (ADR-024) and adds another product dependency. Cognito is the better choice when already on AWS.
Custom auth (Postgres + JWT library): Rejected. Maximum build effort for a solved problem. Security-critical code should not be custom-built when a mature managed service exists.
Signoff record¶
| Date | Name | Role | Status |
|---|---|---|---|
| 2026-04-10 | Ross Millen | CTO | Approved |
| 2026-04-10 | Ross Millen | Head of Architecture | Approved |
| 2026-04-10 | Ross Millen | Head of Data | Approved |
Capabilities¶
| Capability | Description | Relationship |
|---|---|---|
| CAP-024 | Biometric login (Face ID / fingerprint) | enabled — passkey/biometric is the primary login mechanism from onboarding |
| CAP-036 | Passkey / FIDO2 authentication | enabled — WebAuthn passkey registration and challenge are the core auth flow |
| CAP-037 | Step-up authentication for high-value transactions | enabled — second biometric and SMS OTP step-up for payments above threshold |
| CAP-108 | Device registration & trust | enabled — device passkey bound to secure enclave; device ID in JWT claims |
| CAP-109 | Session lifecycle management | enabled — Cognito short-lived JWTs with refresh tokens in device secure enclave |
Related decisions¶
| ADR | Title | Relationship |
|---|---|---|
| ADR-007 | Frontend framework — React/Next.js with Capacitor | Capacitor plugins provide native biometric API access |
| ADR-018 | KYC and digital onboarding architecture | passkey registered at end of onboarding |
| ADR-023 | Cloud provider and region strategy | Cognito in ap-southeast-2 keeps customer identity within region |
| ADR-027 | Internal staff authentication — Cognito and corporate SSO | separate staff Cognito pool with different security policy |
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-026.yaml