#Multi-Factor Authentication (MFA)

8 min read

#Overview

Multi-factor authentication adds an extra layer of security to your AiDial portal account. Sign-in, authenticator setup, MFA challenge, and recovery-code entry are handled by AiDial's identity provider, while the portal checks that your account satisfies the required MFA policy before non-remediation protected pages and actions are available.

#Which Roles Require MFA?

RoleMFA Requirement
Client Administrator (client_admin)Optional
Partner Administrator (partner_admin)Required
AiDial Administrator (aidial_admin)Required
AiDial Operator (aidial_operator)Required
Client Manager (client_manager)Optional
Client Staff (client_staff)Optional
Partner User (partner_user)Optional

For mandatory-MFA roles, the portal treats the session as compliant only after MFA is enrolled and the current sign-in has satisfied the required challenge. If a mandatory-role customer or partner session is not compliant, the portal sends the user to Settings to complete the security step. Internal AiDial administrator/operator sessions use the internal Profile remediation surface.

#Supported Authentication Factors

AiDial Portal currently recognises these MFA factors in portal MFA snapshots built from Zitadel OIDC/session state and, where available, a server-side enrolled-factor lookup:

  • totp: Time-based One-Time Password from a TOTP-compatible authenticator app.
  • recovery_code: Provider-issued recovery code used during sign-in.
  • email_otp: Email one-time code. This is policy-allowed for client_admin and partner_admin only, unless a trusted provider policy claim explicitly allows it for another role.
  • sms_otp: SMS one-time code. Policy-allowed for client_admin and partner_admin only, gated by a per-tenant override (mfa.sms_otp.enabled, default OFF). Internal staff (aidial_admin, aidial_operator) are hard-denied. AU phone numbers only at launch. See sms-otp.md for the customer-facing privacy notice and sub-processor disclosure.
  • webauthn: Passkey or security key. Policy-allowed for client_admin, partner_admin, aidial_admin, and aidial_operator. The portal accepts Zitadel's pinned user AMR value as WebAuthn challenge evidence and never treats generic mfa or otp as WebAuthn.

The portal reports policy-allowed factors separately from factors enrolled by the current user. Operators must not treat allowed_factors as proof that a user has enrolled the factor; use enrolled_factors, enrolled_factors_source, and the current challenge state for that. server_lookup is authoritative. amr_inference_fallback preserves conservative AMR-derived evidence but cannot prove absence and cannot distinguish OTP-class factors from one another.

The portal does not render its own authenticator QR code and does not validate TOTP, email OTP, SMS OTP, passkey, security-key, or recovery-code values directly. Those steps happen in Zitadel.

#How to Enrol in MFA

  1. Sign in to the portal: Use the normal portal sign-in page. If your role requires MFA and the current session is not compliant, the portal redirects you to Settings.
  2. Open MFA setup: In Settings (or Account > Security where the account shell is shown), use Open MFA setup when it is available. The link opens the trusted provider security page for your account. If SMS one-time code is available for your role and organisation, Settings shows a separate SMS factor card.
  3. Complete setup: For TOTP, passkeys/security keys, and recovery codes, follow the provider-hosted Zitadel flow. For SMS one-time code, enter an Australian +61 mobile number in the Settings SMS card; the portal validates the number, forwards it once to Zitadel to create the factor, and does not validate OTP values itself.
  4. Refresh the portal status: Return to the portal and use Refresh security status. This signs in again with a callback to Settings so the portal receives fresh OIDC MFA claims.
  5. Acknowledge recovery-code storage if prompted: After enrolment, re-enablement, or declared recovery-code regeneration, the portal may ask you to confirm that you stored the current recovery-code set.

#Recovery Codes

Recovery codes are managed by Zitadel, not generated or displayed by AiDial Portal. Use them from the provider sign-in flow if you lose access to your authenticator app.

The portal stores only non-secret lifecycle markers for recovery-code acknowledgements and reminders. It does not store raw recovery codes.

#Important Guidelines

  • Store recovery codes securely: Save them in a password manager or print them and keep them in a secure location.
  • Acknowledge storage in the portal when prompted: This records that you stored the current provider-issued set; it does not copy the codes into the portal.
  • Review or regenerate codes in the provider: If a trusted provider management link is available, use it to review or regenerate recovery codes, then refresh the portal status.
  • Respond to recovery-code reminders: If the portal detects a recovery-code sign-in, Settings may remind you to review or regenerate your codes.
  • Never send raw recovery codes to support: Support can guide recovery steps, but users and operators must not paste recovery-code values, authenticator seeds, one-time codes, session cookies, or bearer tokens into tickets or chat.

#Recovery & Lockout

#If You Lose Your Authenticator Device

  1. Use a recovery code in Zitadel: During provider sign-in, use the recovery-code option if it is available for your account.
  2. Review your recovery options: After signing in with a recovery code, the portal may show a reminder in Settings to review or regenerate recovery codes.
  3. Set up a new authenticator device: Use the trusted provider management link from Settings when available, then refresh the portal status.

#If You Have Lost Both Your Authenticator and Recovery Codes

If you cannot access your authenticator app and have no remaining recovery codes:

  1. Contact your organisation's administrator: They may be able to assist with account recovery through the identity provider's administrative tools.
  2. Contact AiDial support: If your administrator is unable to help, contact help@aidial.com.au for further assistance.

The portal cannot bypass MFA on its own, reveal one-time codes, or reset MFA from an unauthenticated browser session. Account recovery is managed through the identity provider and authorised support processes.

#Operator Readiness Checks

The MFA flows depend on the portal's standard required runtime configuration: NEXTAUTH_SECRET, NEXTAUTH_URL, AIDIAL_API_BASE_URL, AIDIAL_API_TIMEOUT_MS, ZITADEL_ISSUER, ZITADEL_CLIENT_ID, and ZITADEL_CLIENT_SECRET. These values are required; the portal code does not define fallback defaults for them.

Before changing MFA provider policy beyond the current portal foundation, operators must complete these development-environment checks and record evidence in the release notes:

  1. Keep the pinned Zitadel AMR and enrolled-factor lookup evidence current for TOTP, recovery code, email OTP, SMS OTP, and WebAuthn/passkey.
  2. Confirm whether Zitadel exposes enrolled factors in OIDC claims or requires the server-side enrolled-factor lookup, and document when the portal is using AMR inference fallback.
  3. Verify client_admin, partner_admin, aidial_admin, and aidial_operator can use WebAuthn only where policy allows it.
  4. Verify aidial_admin and aidial_operator cannot satisfy mandatory MFA with email OTP or SMS OTP unless an explicit approved provider policy and portal implementation allow it.
  5. Verify recovery-code sign-in still shows the recovery-code-first remediation path.
  6. Verify APP 5 collection notice copy is presented before collecting a phone number or alternate email address for OTP enrolment.
  7. Verify audit metadata contains only safe factor identifiers and marker IDs, not OTPs, email addresses, phone numbers, tokens, cookies, or recovery codes.

Internal operators should consult the AiDial operations runbooks for the current pinned-claim table, recorded live evidence, and the safe path to enable email OTP in development without changing customer-facing Zitadel policy. This guide stays focused on portal end-user behaviour.

#Passkey / Security Key Gate

Passkeys and security keys are provider-hosted in Zitadel. The portal does not store WebAuthn credential IDs, public keys, attestation, assertions, challenges, or raw recovery codes. Profile pages may show a device label and last-used timestamp when Zitadel's enrolled-factor lookup returns those safe fields.

The portal accepts only the pinned Zitadel user AMR value as WebAuthn challenge evidence. Generic mfa or otp AMR values are not enough to identify a passkey/security-key challenge.

Recovery codes remain provider-managed. Because Zitadel maps recovery-code authentication to generic otp, the portal does not infer recovery-code use from otp; recovery-code lifecycle reminders continue to rely on the existing explicit marker paths.

#SMS OTP Gate

SMS OTP enrolment is implemented but remains deny-by-default unless both the role policy and tenant override allow it. The Settings SMS factor card is hidden unless allowed_factors includes sms_otp. When it is visible, it shows the APP 5 notice before collecting an Australian +61 mobile number.

POST /api/auth/mfa-sms-enrol enforces CSRF/session auth, permits only client_admin and partner_admin, requires the mfa.sms_otp.enabled tenant override, validates AU E.164 numbers, applies rate limits, forwards the number once to Zitadel's otp_sms factor endpoint, and discards the plaintext. Responses and audit metadata use the masked phone tail only, with forbidden fields redacted.

SMS OTP challenge evidence must not be inferred from generic mfa or otp AMR values. Current parsers keep sms_otp AMR aliases empty; enrolled SMS state comes from the server-side Zitadel enrolled-factor lookup when available. If the provider integration is unavailable, SMS enrolment fails closed with a provider-unavailable response.

#Disabling MFA

  • Roles that require MFA (partner_admin, aidial_admin, aidial_operator) cannot disable MFA while assigned to that role.
  • Optional-MFA roles can launch trusted provider MFA management from Settings or Account Security only when the current lifecycle state allows it and a trusted provider management URL is available.
  • The portal does not disable the factor directly. It records the launch request and opens the provider management flow.
  • After changing MFA in the provider, refresh the portal security status so the current session reflects the new state.

#Next Steps