WordPress Two-Factor Authentication: Code vs Plugin Implementation

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.

Leave Comment

Your email address will not be published. Required fields are marked *