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
| Method | How the code arrives | Best for |
|---|---|---|
| Passkey | A browser prompt for your device, security key or password manager | Domain-bound device verification; see Passkeys |
| Email code | A one-time code emailed to the user’s address | Sites 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 app | Anyone 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.
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.
Settings
Under Settings → General Settings → Two-Factor Authentication:
| Setting | Meaning |
|---|---|
| Passkey | Enable device verification for selected roles; see Passkeys |
| Email code | On or off |
| Email code roles | Roles that must enter an emailed code (default: Administrator, Editor, Author) |
| Authenticator app | On or off |
| Authenticator App: Roles allowed to set one up | Roles that may enrol an authenticator. Empty means nobody can |
| Authenticator App: Roles that must set one up | Roles 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:
- Scan the QR code, or type the secret into the app by hand.
- Enter the current six-digit code to prove the app is set up.
- 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:
- Add
FLUENT_AUTH_SECURITY_KEYtowp-config.php. Any long random string will do. - 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
| Hook | Purpose |
|---|---|
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 |