Docs / Login security

Two-factor authentication

Configure passkeys, authenticator apps and email verification by role, with recovery codes and enforcement.

All documentation

A second factor means a stolen or guessed password is not enough to get in. FluentAuth supports three methods and applies them per role, so administrators can be required to use one while subscribers are never asked.

Methods

MethodHow the code arrivesBest for
PasskeyA browser prompt for your device, security key or password managerDomain-bound device verification; see Passkeys
Email codeA one-time code emailed to the user’s addressSites where everyone can read their email at login time; no app to install
Authenticator app (TOTP)A six-digit code from Google Authenticator, 1Password, Authy, Microsoft Authenticator or any TOTP appAnyone who can carry a phone; works offline and does not depend on email delivery

A usable passkey is offered ahead of an authenticator app. Enrolled device methods take priority over email. A magic link already proves access to the mailbox, so it skips an email code but does not satisfy a required device factor.

SINCE 3.0

Passkeys, authenticator-app codes, recovery codes, the enrolment list and required-role enforcement were added in FluentAuth 3.0.0. Email codes have been available since 1.0.

Two-factor settings showing passkeys, authenticator apps and email codes.

Settings

Under Settings → General Settings → Two-Factor Authentication:

SettingMeaning
PasskeyEnable device verification for selected roles; see Passkeys
Email codeOn or off
Email code rolesRoles that must enter an emailed code (default: Administrator, Editor, Author)
Authenticator appOn or off
Authenticator App: Roles allowed to set one upRoles that may enrol an authenticator. Empty means nobody can
Authenticator App: Roles that must set one upRoles that must have an authenticator before they can use wp-admin. Must be a subset of the roles above

A role can be in both email and authenticator lists. Users in that role get email codes until they enrol an app, then app codes.

Enrolling an authenticator

Users enrol from their own profile (Users → Profile → Two-Factor Authentication), or from the standalone setup page at wp-login.php?action=fls_2fa_setup, which works without wp-admin access. Enrolment is:

  1. Scan the QR code, or type the secret into the app by hand.
  2. Enter the current six-digit code to prove the app is set up.
  3. Save the ten recovery codes shown once. Each works one time in place of an app code.

The QR code is drawn by the plugin itself. Nothing about the secret leaves your server.

Encrypting stored secrets

An authenticator secret is the one credential FluentAuth has to be able to read back, because a code is checked by generating it. It cannot be hashed the way a password or a recovery code is. So it can be encrypted instead, with a key you keep out of the database:

  1. Add FLUENT_AUTH_SECURITY_KEY to wp-config.php. Any long random string will do.
  2. Turn Encrypt stored secrets on under the authenticator app settings.

Existing enrolments are encrypted in place, and a copy of your database stops being enough to generate anybody’s codes. If the key later goes missing or changes, FluentAuth says which of the two happened and both are recoverable while you still have the old value. See Constants.

What the user sees

After a correct password, a second screen asks for the code. Five wrong codes end the attempt, and a pending challenge expires after ten minutes. Both outcomes are logged.

Users whose role is in Roles that must set one up and who have not enrolled are shown the setup page instead of the dashboard until they do. Users whose role may enrol but is not required see a one-time nudge after login, dismissible; the fluent_auth/ask_to_set_up_totp filter turns that off.

Managing enrolments

Settings → 2FA Enrollment lists every user in an eligible role with whether they have an device methods, searchable and filterable. Review the enrolled methods and reset the affected method for someone who has lost access. Passkeys can also be managed from the user profile.

Logins that skip the form

The second factor is also enforced for logins that never show the login form: application passwords, social logins, and code that calls wp_set_auth_cookie() directly. A user whose role requires a factor cannot get a session without one by any route. To exempt a specific integration, use the fluent_auth/enforce_2fa_on_auth_cookie filter.

WP-CLI is exempt, so wp user session create and similar still work from the server.

Recovery

  • Lost the phone: use a recovery code, then reset and re-enrol from the profile.
  • Lost the phone and the codes: another administrator resets you from 2FA Enrollment.
  • Only administrator, lost everything: see Troubleshooting for the server-access recovery procedure.

Developer hooks

HookPurpose
fluent_auth/2fa_challenge_required (filter)Require a challenge for a user whose role does not. It cannot waive one
fluent_auth/2fa_methods (filter)Add or remove methods
fluent_auth/totp_enabled (filter)Offer the authenticator app to this user, or not
fluent_auth/totp_activated, totp_disabled (actions)React to enrolment events
fluent_auth/recovery_codes_generated, recovery_code_used (actions)A set was issued, or one was spent
fluent_auth/2fa_code_request_limit, 2fa_code_request_timing (filters)Rate limit for emailed codes