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
| Feature | Detail |
|---|---|
| Authenticator support | Any RFC 6238 app: Google Authenticator, Authy, 1Password, Microsoft Authenticator, Bitwarden, or the PasswordGenerator.now wallet |
| Enrollment | QR code drawn in your browser - The secret never leaves your server |
| Backup codes | Ten single-use codes, shown once, stored only as hashes, regenerable |
| Brute-force defence | 15-minute lockout after 5 wrong codes |
| Replay protection | A code cannot be reused inside its own 30-second window |
| Role enforcement | Require 2FA for administrators, editors or any role |
| Admin visibility | A 2FA column on the Users list shows who is protected |
| Clean uninstall | Deleting 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.
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):
- Sign in to your site as an administrator.
- In the left sidebar go to Plugins → Add New Plugin.
- Click Upload Plugin at the top of the page.
- Click Choose File, select the ZIP you just downloaded, then click Install Now.
- When it finishes, click Activate Plugin.
If your host blocks plugin uploads (some managed hosts do), install it over FTP or SFTP instead:
- Unzip
pgn-2fa.zipon your computer — You should get a single folder namedpgn-2fa. - Connect to your server and open
/wp-content/plugins/. - Upload the whole
pgn-2fafolder into it, so the main file ends up at/wp-content/plugins/pgn-2fa/pgn-2fa.php. - 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.
- In WordPress go to Users → Profile (or click your name, top right).
- Scroll down to the Two-Factor Authentication section.
- 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.
- 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.
- 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
- Go to Settings → Two-Factor Auth.
- Tick the roles that must use 2FA — Administrator and Editor are the usual choices.
- 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.
- You enter your username and password on the normal WordPress login screen, as always.
- 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.
- Open your authenticator app, type the current code, and click Verify.
- 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:
- 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.
- No other admin? Rename the plugin folder over FTP or SSH —
change
/wp-content/plugins/pgn-2fatopgn-2fa-off. WordPress deactivates it automatically and you can log in with just your password. Rename it back afterwards and re-enroll. - Database access only? Delete the row in the
wp_usermetatable wheremeta_keyis_pgn_2fa_enabledanduser_idis 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?
Why doesn't the plugin use your 2FA API?
What happens if a user loses their phone?
Will it break my existing logins or my REST API?
Is the attribution link required?
Is the code auditable?
Found a bug or a security issue? Tell us - Security reports are answered within 48 hours.