Two-factor authentication dramatically reduces the impact of stolen passwords on WordPress admin accounts. You can implement TOTP-based 2FA with a few lines of code using a PHP TOTP library, or integrate it cleanly via a battle-tested plugin — knowing both options lets you choose the right trade-off.
Problem: WordPress uses a single password for admin access with no second factor — a leaked or brute-forced password gives an attacker full control of the site immediately.
Solution: Add TOTP-based two-factor authentication: use the Two-Factor plugin for a no-code solution that adds an authenticator app flow to the standard login form, or implement it with a custom plugin using a TOTP library — generate a secret per user, display it as a QR code during setup, then verify the six-digit code on every login with authenticate and wp_authenticate_user hooks.
The examples below show how to enforce 2FA for specific user roles, generate and verify TOTP codes with the RobThree/TwoFactorAuth library, and configure the free Two-Factor plugin for admin-only enforcement.
<?php
// Using RobThree/TwoFactorAuth (install: composer require robthree/twofactorauth)
use RobThree\Auth\TwoFactorAuth;
use RobThree\Auth\Providers\Qr\GoogleChartsQrCodeProvider;
$tfa = new TwoFactorAuth( new GoogleChartsQrCodeProvider(), 'MyWordPressSite' );
// 1. Generate a secret for a new user (store in usermeta)
$secret = $tfa->createSecret();
update_user_meta( $user_id, '_2fa_secret', $secret );
update_user_meta( $user_id, '_2fa_enabled', false ); // not confirmed yet
// 2. Show QR code on the profile page
$qr_url = $tfa->getQRCodeImageAsDataUri( $user->user_login, $secret );
echo '<img src="' . esc_attr( $qr_url ) . '" alt="Scan with authenticator app">';
// 3. Verify the code entered by the user (e.g., on a custom login step)
$code = sanitize_text_field( $_POST['2fa_code'] ?? '' );
$secret = get_user_meta( $user_id, '_2fa_secret', true );
if ( $tfa->verifyCode( $secret, $code ) ) {
update_user_meta( $user_id, '_2fa_enabled', true );
// proceed with login
} else {
wp_die( 'Invalid 2FA code' );
}
Enforce 2FA for admins using the free Two-Factor plugin (WordPress.org):
<?php
// Enforce 2FA for administrators — redirect to profile page if 2FA is not configured.
// Requires the "Two-Factor" plugin (wordpress.org/plugins/two-factor/) to be active.
add_action( 'wp_login', function( string $user_login, WP_User $user ) {
if ( ! in_array( 'administrator', (array) $user->roles, true ) ) return;
// Check if Two-Factor plugin is active
if ( ! function_exists( 'Two_Factor_Core::is_user_using_two_factor' ) ) return;
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( ! Two_Factor_Core::is_user_using_two_factor( $user->ID ) ) {
// Redirect to profile to set up 2FA before reaching admin
wp_redirect( admin_url( 'profile.php#two-factor-options' ) );
exit;
}
}, 10, 2 );
// Force 2FA setup notice in the admin
add_action( 'admin_notices', function() {
if ( ! current_user_can( 'administrator' ) ) return;
if ( ! function_exists( 'Two_Factor_Core::is_user_using_two_factor' ) ) return;
if ( Two_Factor_Core::is_user_using_two_factor( get_current_user_id() ) ) return;
echo '<div class="notice notice-error"><p><strong>Security:</strong> '
. 'Two-factor authentication is required for administrator accounts. '
. '<a href="' . esc_url( admin_url( 'profile.php#two-factor-options' ) ) . '">Set up 2FA now</a>.</p></div>';
} );
NOTE: For most sites, the Two-Factor plugin is the better choice — it handles backup codes, email fallback, and recovery. Custom TOTP code makes sense only when you need to integrate 2FA into a fully headless or non-standard login flow.