Turn on two-factor authentication
Users manage authenticator (TOTP) two-factor authentication through /identity/manage/2fa. POST requires a signed-in user, a CSRF token in the RequestVerificationToken header, and a fresh ReAuth proof. The body is Identity's TwoFactorRequest.
The steps assume a cookie session. Send credentials: 'include' and get a CSRF token from GET /identity/csrfToken before each POST. To sign in after 2FA is on, see Enter a two-factor code or a recovery code.
Video
Read the 2FA status
Send GET /identity/manage/2fa. The response is { "isTwoFactorEnabled": true } or false. This route needs no CSRF token and no ReAuth.
Turn on 2FA
- Complete step-up. See Require step-up before sensitive actions.
- Send
POST /identity/manage/2fawith the body{}. If the user has no authenticator key, the response includes a newsharedKey. - Show the shared key, or a QR code made from it, so that the user can add it to an authenticator app.
- If the ReAuth proof expired, complete step-up again. The default lifetime is 5 minutes (
ReAuth.Lifetime). - Send
POST /identity/manage/2fawith{ "enable": true, "twoFactorCode": "<6-digit code>" }. - On
200, show therecoveryCodesfrom the response. When the user has no recovery codes left, turning on 2FA issues 10 new codes. The response also hasisTwoFactorEnabled: true.
Do not send enable: true together with resetSharedKey: true. That request returns a validation problem with the key CannotResetSharedKeyAndEnable.
These validation problems can also come back from step 5:
RequiresTwoFactor: the request had notwoFactorCode.InvalidTwoFactorCode: the code did not match the shared key.
Turn off 2FA
- Complete step-up.
- Send
POST /identity/manage/2fawith{ "enable": false }. - On
200, the response hasisTwoFactorEnabled: false.
To rotate the authenticator key, send { "resetSharedKey": true }. That request also turns 2FA off. Turn it on again with a code from the new key.
Use the other request fields
| Field | Effect |
|---|---|
resetRecoveryCodes | Issues 10 new recovery codes and returns them in recoveryCodes. |
forgetMachine | Clears the two-factor remember-client cookie. |
A persistent cookie login with a valid authenticator code sets the remember-client cookie. Later password logins from that browser skip the 2FA challenge until the user sends forgetMachine or logs out. See Remembered browsers.
Know which sign-ins skip 2FA
Passkey sign-in and GitHub or Google sign-in do not ask for a 2FA code, even when 2FA is on. See Security model.