WordPress 2FA Plugin

Add two-factor authentication to any WordPress site in about two minutes. Free, open source, and verified entirely on your server - No API key, no account, no calls to us.

Version 1.0.0 · GPLv2 · Requires WordPress 5.6+ and PHP 7.2+

Why This Plugin Is Different

Most "free" 2FA plugins route your logins through someone else's servers, or hold the good parts back for a paid tier. This one does neither, and the reason is a security argument rather than a generosity one.

No API call at login

Codes are verified in PHP on your own server using standard TOTP. If this site went offline tomorrow, your logins would be completely unaffected - A login path that depends on a third party's uptime is a liability, not a feature.

Secrets encrypted at rest

Each TOTP seed is encrypted with a key derived from your site salts, so a leaked database dump alone doesn't hand over working seeds - The attacker would also need your wp-config.php.

Nothing phones home

There is no network request anywhere in the plugin. No telemetry, no licence check, no "anonymous usage data". The optional login-screen credit is a plain link you can switch off.

What's Included

FeatureDetail
Authenticator supportAny RFC 6238 app: Google Authenticator, Authy, 1Password, Microsoft Authenticator, Bitwarden, or the PasswordGenerator.now wallet
EnrollmentQR code drawn in your browser - The secret never leaves your server
Backup codesTen single-use codes, shown once, stored only as hashes, regenerable
Brute-force defence15-minute lockout after 5 wrong codes
Replay protectionA code cannot be reused inside its own 30-second window
Role enforcementRequire 2FA for administrators, editors or any role
Admin visibilityA 2FA column on the Users list shows who is protected
Clean uninstallDeleting the plugin removes every stored secret and setting

Step-by-Step Installation

Takes about two minutes. You need administrator access to your WordPress site and a phone with an authenticator app. Activating the plugin changes nothing for anyone until a user personally enrolls, so it is safe to install on a live site during working hours.

Step 1 — Download the plugin

Click the button below and save the file. Do not unzip it — WordPress wants the ZIP exactly as downloaded.

Download pgn-2fa.zip (32 KB)

Verifying the file is good practice for anything security-related. On macOS or Linux run shasum -a 256 pgn-2fa.zip, or on Windows PowerShell Get-FileHash pgn-2fa.zip -Algorithm SHA256. It should print:

1d164381eeb597bb072c18ed112b3c47fe7ee7d18d0020309ab345805cbfccdb

Step 2 — Install it in WordPress

The normal way (through the admin screen):

  1. Sign in to your site as an administrator.
  2. In the left sidebar go to Plugins → Add New Plugin.
  3. Click Upload Plugin at the top of the page.
  4. Click Choose File, select the ZIP you just downloaded, then click Install Now.
  5. When it finishes, click Activate Plugin.

If your host blocks plugin uploads (some managed hosts do), install it over FTP or SFTP instead:

  1. Unzip pgn-2fa.zip on your computer — You should get a single folder named pgn-2fa.
  2. Connect to your server and open /wp-content/plugins/.
  3. Upload the whole pgn-2fa folder into it, so the main file ends up at /wp-content/plugins/pgn-2fa/pgn-2fa.php.
  4. Back in WordPress go to Plugins, find Two-Factor Authentication by PasswordGenerator.now, and click Activate.

Step 3 — Turn on 2FA for your own account

Install an authenticator app on your phone first if you don't have one. Any of these work: Google Authenticator, Authy, Microsoft Authenticator, 1Password, Bitwarden, or the free PasswordGenerator.now wallet in your browser.

  1. In WordPress go to Users → Profile (or click your name, top right).
  2. Scroll down to the Two-Factor Authentication section.
  3. Open your authenticator app, choose add account or the + button, and scan the QR code shown on the page. If you can't scan, type the key printed beside it instead.
  4. Your app now shows a 6-digit code that changes every 30 seconds. Type the current code into the Enter the 6-digit code to confirm box.
  5. Scroll to the bottom and click Update Profile.

If the code is refused, see "My code is always rejected" in the troubleshooting section below — It is almost always a clock problem, and it is fixable in seconds.

Step 4 — Save your backup codes (do not skip this)

The moment 2FA switches on, WordPress shows ten backup codes in a green box at the top of the screen. Each one works as a substitute for the 6-digit code, exactly once.

They are displayed only this one time. We store only hashes of them, so nobody — including you — can retrieve them later.

Copy them somewhere you will still have access to if your phone is lost, stolen or wiped: a password vault on another device, a printed sheet in a drawer, or a password manager you already use. Saving them only on the phone that holds your authenticator defeats the purpose.

Step 5 — Optional: require 2FA for your team

  1. Go to Settings → Two-Factor Auth.
  2. Tick the roles that must use 2FA — Administrator and Editor are the usual choices.
  3. Click Save Changes.

Anyone in those roles who has not enrolled is sent to their profile page to set it up the next time they visit the admin area. They are not locked out and existing sessions are not broken — They simply can't do anything else in the admin until they enroll.

Enroll yourself before switching this on, and check the 2FA column on the Users screen to see who is protected.

What Signing In Looks Like Afterwards

Nothing about the first screen changes, so there is nothing new to teach anyone.

  1. You enter your username and password on the normal WordPress login screen, as always.
  2. If the password is correct, a second screen appears asking for your 6-digit code. You are not signed in yet at this point — No session exists until the code is accepted.
  3. Open your authenticator app, type the current code, and click Verify.
  4. You land wherever you were headed. Ticking Remember Me on the first screen still works normally.

Lost your phone? Type one of your backup codes into the same box instead of the 6-digit code.

Troubleshooting

"My code is always rejected"

TOTP codes are derived from the current time, so this is nearly always a clock that has drifted — on the phone or on the server.

  • On your phone: turn on automatic date and time. On Android it is Settings → System → Date & time; on iPhone, Settings → General → Date & Time → Set Automatically. In Google Authenticator you can also use Settings → Time correction for codes → Sync now.
  • Check you are reading the right entry if your app holds several accounts — The entry is named after your site.
  • Type it quickly. Codes last 30 seconds; the plugin accepts the step either side, so small drift is already tolerated.
  • If it still fails, your server's clock may be wrong. Ask your host to check NTP synchronisation.

"Too many incorrect codes"

Five wrong codes trigger a 15-minute lockout on that account. That is deliberate — it is what stops someone guessing codes. Wait it out, then fix the clock as above. Your password is unaffected.

"I lost my phone AND my backup codes"

In order of preference:

  1. Ask another administrator to open Users → (your account) → Edit, tick Turn off two-factor authentication for this account, and save. You can then re-enroll.
  2. No other admin? Rename the plugin folder over FTP or SSH — change /wp-content/plugins/pgn-2fa to pgn-2fa-off. WordPress deactivates it automatically and you can log in with just your password. Rename it back afterwards and re-enroll.
  3. Database access only? Delete the row in the wp_usermeta table where meta_key is _pgn_2fa_enabled and user_id is yours.

This is exactly why Step 4 matters. Save the backup codes.

Removing the plugin

Deactivating it immediately stops 2FA prompts — Everyone signs in with just a password again. Deleting it goes further and erases every stored secret, backup code and setting, so a later reinstall starts clean and no 2FA data is left behind in your database.

Questions

Do I need an API key or an account to use the plugin?
No. The plugin is completely self-contained: it generates and verifies TOTP codes in PHP on your own server. There is no API key, no account, and no network request anywhere in the code - Which is exactly why your logins keep working even if this website is down.
Why doesn't the plugin use your 2FA API?
Because it would make your logins depend on our uptime, and it would mean your users' 2FA secrets travelling to a third party. Neither is acceptable for an authentication path. The API exists for projects that are not WordPress and want a hosted option; the plugin is the right architecture for WordPress.
What happens if a user loses their phone?
They use one of the ten single-use backup codes issued at setup. If those are gone too, any administrator can switch 2FA off for that user from the user edit screen. A locked-out sole administrator can deactivate the plugin over FTP or SSH, or delete the _pgn_2fa_enabled user meta row directly.
Will it break my existing logins or my REST API?
No. Nothing changes for a user until they personally enroll, so activating it on a live site is safe. Application passwords and XML-RPC are deliberately not intercepted, since those flows cannot show an interactive code prompt.
Is the attribution link required?
No - It is a checkbox in Settings, and the plugin behaves identically with it off. It is a plain HTML link with no tracking parameters. Leaving it on is simply how other people discover the project.
Is the code auditable?
Yes. It is GPLv2, about 900 lines of readable PHP, with no build step, no minified blobs and no external dependencies apart from a bundled MIT-licensed QR drawing library. The TOTP implementation is verified against the official RFC 6238 test vectors.

Found a bug or a security issue? Tell us - Security reports are answered within 48 hours.