docs(two-factor): merge enforcement-scope clarification into OTP rewrite (#9607)

Layers main's #9607 clarification onto next's #9057 OTP-enablement rewrite.
The "Sign In with 2FA" section now states that 2FA sign-in enforcement
applies to the credential endpoints (/sign-in/email, /sign-in/username,
/sign-in/phone-number) and that passwordless flows are not gated by default,
with guidance to add custom hook handling to require it. The passwordless
callout and the allowPasswordless option note that the flag does not change
which sign-in methods are challenged. main's edit to the removed
skipVerificationOnEnable bullet is dropped, since next deleted that option.

(cherry picked from commit 6156cef51329e1c38544aa06eb5072d8a06ece7a)
This commit is contained in:
Gustavo Valverde
2026-05-31 00:10:36 +01:00
parent 027a10c566
commit be653ab90d
+7 -3
View File
@@ -90,7 +90,7 @@ To enable two-factor authentication, call `twoFactor.enable`. The user must prov
* **`otp`** — enables email/SMS-based codes immediately, with no extra verification step. Returns `{ method: "otp" }`. Requires `otpOptions.sendOTP` to be configured on the server.
<Callout type="warn">
By default, enabling 2FA requires a password. Users who signed up via OAuth, passkeys, magic links, or anonymous auth cannot enable 2FA unless you set `allowPasswordless: true` in the plugin config.
By default, enabling 2FA requires a password. Users who signed up via OAuth, passkeys, magic links, or anonymous auth cannot enable 2FA unless you set `allowPasswordless: true` in the plugin config. This option does not change which sign-in methods are challenged for 2FA.
</Callout>
<APIMethod path="/two-factor/enable" method="POST" requireSession>
@@ -125,7 +125,11 @@ When `method` is `"otp"`:
### Sign In with 2FA
When a user with 2FA enabled tries to sign in via email, the response object will contain `twoFactorRedirect` set to `true` and `twoFactorMethods` — an array of the 2FA methods available for the user (e.g. `["totp"]`, `["totp", "otp"]`). Use `twoFactorMethods` to decide which verification UI to show.
When a user with 2FA enabled tries to sign in via email, username, or phone number, the response object will contain `twoFactorRedirect` set to `true` and `twoFactorMethods` — an array of the 2FA methods available for the user (e.g. `["totp"]`, `["totp", "otp"]`). Use `twoFactorMethods` to decide which verification UI to show.
By default, 2FA sign-in enforcement applies to the credential-based sign-in endpoints: `/sign-in/email`, `/sign-in/username`, and `/sign-in/phone-number`. Non-credential sign-in methods such as email OTP, magic link, OAuth/social, passkey, anonymous, and similar passwordless flows are not gated by 2FA by default.
If your app needs to require 2FA for those sign-in methods, add custom hook handling for those endpoints and redirect users into your 2FA verification flow before treating the sign-in as complete.
You can handle this in the `onSuccess` callback or by providing a `onTwoFactorRedirect` callback in the plugin config.
@@ -518,7 +522,7 @@ export const twoFactorTableFields = [
**issuer**: Custom issuer name for the TOTP URI. Defaults to your `appName`.
**allowPasswordless**: Allow enabling and managing 2FA without a password for users that do not have a credential account. Password is still required if a credential account exists.
**allowPasswordless**: Allow enabling and managing 2FA without a password for users that do not have a credential account. Password is still required if a credential account exists. This option does not change which sign-in methods are challenged for 2FA.
**Issuer**: The issuer is the name of your application. It's used to generate TOTP codes. It'll be displayed in the authenticator apps.