Account security
Two-step verification
Section titled “Two-step verification”A user turns on two-step verification by adding an authenticator app (TOTP) or a passkey. The first method a user adds gives them 10 single-use backup codes; removing the last method turns two-step verification off. From then on a sign-in with a password, an email code or a social provider asks for a second factor: an authenticator app code, a backup code or a passkey.
When Auth settings require two-step verification, a user without it signs in to a pending session with the
task setup_mfa: it gets no session token until they add a method. Users then cannot remove their last method. A user
who lost their devices can have it removed in the dashboard or with the Backend API
(DELETE /v1/backend/users/{userId}/mfa), which also ends their sessions.
Passkeys
Section titled “Passkeys”A passkey signs a user in on its own: it is both factors, and never asks for a second step. It can also be the second factor after a password. A passkey belongs to a domain (its RP ID):
- Production: your domain (
example.comforaccounts.example.com), so a passkey added in your app onapp.example.comalso works on the hosted pages, and the other way round. - Development: each page’s own host, so a passkey added on
localhostdoes not work on the hosted pages and the other way round.
Passkeys work only over HTTPS or on http://localhost, never on an IP address such as 127.0.0.1
(passkey_origin_unsupported). An account has at most 10.
Reverification
Section titled “Reverification”Sensitive account changes need a recent identity check, not just a signed-in session: changing the password or the
email addresses, adding or removing an authenticator app, backup codes or passkeys, connecting or removing a social
account, and deleting the account. Zautha asks for the second factor (or the first, for a user without two-step
verification) within the last 10 minutes, and otherwise answers
reverification_required; the components ask the user to verify again and
retry.
Your own sensitive endpoints can ask for the same. The session token’s fva claim says how many minutes ago the
session verified each factor, and every server SDK checks it:
| Requirement | Window | User with two-step verification | User without it |
|---|---|---|---|
strict |
10 minutes | second factor | first factor |
moderate |
1 hour | second factor | first factor |
lax |
1 day | second factor | first factor |
strict_mfa |
10 minutes | both factors | first factor |
A custom requirement sets the window (1 to 1,440 minutes) and the level (first_factor, second_factor or
multi_factor). The first factor is the password, an email code or a link; the second is an authenticator app code
or a backup code; a passkey can be either. When a check fails, your endpoint answers 403 reverification_required and
useReverification (@zautha/react) asks the user to verify that level and retries. See
@zautha/backend,
@zautha/nextjs and
Zautha.AspNetCore.
An impersonation session never passes a reverification check.