# NexaMFA Security ## Threat Model NexaMFA assumes the network, push transport, and user-facing login prompts can be attacked. Security depends on server-issued challenge payloads, local Android confirmation, asymmetric signatures, server-side verification, expiry, and single-use state transitions. ## Challenge Payload Each challenge contains: - `challenge_id` - `user_id` - `username` - `relying_party` - `requester_ip` - `location` - `issued_at` - `expires_at` - `nonce` The Android app displays these details before approval. After BiometricPrompt succeeds using fingerprint, face unlock, or device credential, the app signs the canonical JSON payload. The server verifies the signature against the enrolled public key. ## Controls - Private keys are generated in Android Keystore and never leave the device. - Push notifications contain only `challenge_id`. - Challenges expire after `CHALLENGE_TTL_SECONDS`, default 60 seconds. - Approved, denied, and expired challenges cannot be reused. - Revoked devices cannot approve challenges. - Deny, timeout, invalid signature, replay attempts, enrollment, and revocation are audit logged. - Admin APIs require bearer-token authentication and should be reverse-proxy restricted. - Prometheus metrics should be network restricted. ## Operational Guidance - Rotate admin and OIDC secrets on suspected disclosure. - Revoke lost devices immediately. - Keep Firebase credentials outside Git. - Use HTTPS end to end from clients to Zoraxy. - Back up PostgreSQL and the OIDC signing key. ## Known Hardening Backlog - Add Android hardware attestation enforcement. - Replace the FCM service stub with google-auth OAuth2 token minting in `PushService`. - Add admin SSO instead of static bearer token for large deployments. - Add per-user device selection and policy rules.