First release.
An add-on for the Two Factor plugin. When a user you have chosen to cover signs in without a second factor, this enrolls them then and there: WordPress emails them a one-time code, withholds the login cookie until they enter it, and records the enrollment once they do.
Entering that code proves they control the mailbox, so proving the factor and setting it up are the same step. There is no separate setup wizard to finish later, and no window in which the user is signed in without a second factor.
What it does
- Enrollment happens before a session exists. The Email provider is pre-enabled for a covered user, so
Two_Factor_Core::filter_authenticate()withholds the auth cookie and Two Factor's own challenge performs the enrollment. - No policy of its own. Two filters decide who is covered and who may defer —
two_factor_enrollment_requiredandtwo_factor_enrollment_deferrable— and both default tofalse. Installing the plugin alone changes nothing. - A one-time onboarding screen. Ten backup codes, enabled as a working recovery method rather than only displayed, with download and copy, plus an optional authenticator-app upgrade. Continue is held back until the codes are acknowledged — and stays a working link where JavaScript does not run.
- Signals for the policy layer.
two_factor_enrollment_enrolledfires once per user, and a notification email is sent, when enrollment is first recorded. - Tells you when it cannot work. Admin notices for the Email provider being disabled site-wide, or no policy filter being registered. The latter also appears in Network Admin.
- Leaves nothing behind. One user meta key, removed on uninstall, network-wide on multisite.
Why the required path offers no choice of method
A forced-enrollment screen that lets the user pick their factor hands the second factor to whoever arrives first holding the password. An attacker with a stolen password would enroll their own authenticator and never need the victim's mailbox. Requiring a factor that depends on a channel the password-holder does not already control is what closes that race, so the required path offers exactly one factor. See docs/README.md for the full reasoning.
Requirements
WordPress 6.5+, PHP 7.2+, and the Two Factor plugin active.
Installing
Download two-factor-enrollment-0.1.0.zip below and install it through Plugins → Add New → Upload Plugin, or unzip it into wp-content/plugins/. Activate Two Factor first — this plugin declares it under Requires Plugins and WordPress will refuse to activate before it.
Then register a policy, or nothing will happen:
add_filter( 'two_factor_enrollment_required', function ( $required, $user ) {
return user_can( $user, 'edit_posts' );
}, 10, 2 );Tested
189 tests across three suites (single-site, multisite, and one proving the plugin no-ops when Two Factor is absent). CI covers PHP 7.2/WP 6.9, 7.4, 8.1 and 8.3 against latest, 8.3 against trunk, plus a multisite leg and a check that the built zip actually installs and activates.