Title: SPIDY 2FA LOGIN
Author: carlocozzetto
Published: <strong>25 Luj 2026</strong>
Last modified: 27 Setember 2026

---

Search plugins

![](https://ps.w.org/spidy-2fa-login/assets/banner-772x250.png?rev=3622361)

![](https://ps.w.org/spidy-2fa-login/assets/icon-256x256.png?rev=3622361)

# SPIDY 2FA LOGIN

 By [carlocozzetto](https://profiles.wordpress.org/carlocozzetto/)

[Download](https://downloads.wordpress.org/plugin/spidy-2fa-login.2.0.3.zip)

 * [Details](https://lmo.wordpress.org/plugins/spidy-2fa-login/#description)
 * [Reviews](https://lmo.wordpress.org/plugins/spidy-2fa-login/#reviews)
 * [Development](https://lmo.wordpress.org/plugins/spidy-2fa-login/#developers)

 [Support](https://wordpress.org/support/plugin/spidy-2fa-login/)

## Description

**SPIDY 2FA LOGIN** adds a second layer of security to the WordPress login: after
entering the correct password, the user is asked for a 6-digit code (email or SMS)
or a biometric confirmation (fingerprint / Face ID via WebAuthn), depending on the
method chosen for that account.

#### Why it’s different

Most two-factor plugins fall into one of two categories: dedicated 2FA plugins that
rely on a separate authenticator app (Google Authenticator, Authy, and similar TOTP
apps the user has to install and set up before they can even log in), or full security
suites where 2FA is one small feature buried inside a much heavier toolkit of malware
scanning, firewalls, and file monitoring — useful if you need all of that, overkill
if you just want a second login step.

SPIDY 2FA LOGIN doesn’t ask the user to install anything. Email and SMS just work
with a code. Biometric login uses the device’s own fingerprint sensor, Face ID, 
or a passkey already saved in the browser — the same technology behind passwordless
sign-in on major websites — with automatic fallback to email if it’s ever unavailable,
so nobody gets permanently locked out. Three methods, one plugin, nothing extra 
to install on either side.

#### What’s included

 * Two-factor authentication via email code
 * Optional SMS delivery via your own Twilio or Clickatell account (pay-as-you-go
   pricing set by the provider you choose)
 * Biometric login (fingerprint / Face ID / passkey) via the WebAuthn/FIDO2 standard—
   requires PHP 8.2+ and an HTTPS site; falls back to email automatically if unavailable
   or no device is registered
 * One-time backup codes: each user can generate 10 printable codes to sign in when
   the email or SMS code doesn’t arrive
 * Emergency switch: a single line in wp-config.php (`define( 'SPIDY_2FA_OFF', true);`)
   disables 2FA for everyone — no need to rename or delete the plugin folder
 * Simple, immediate user management panel with per-user method selection
 * No user cap
 * Translation-ready (all strings use the `spidy-2fa-login` text domain) — ready
   to receive community translations via translate.wordpress.org once listed

#### Testing environment

This plugin has always been developed and tested exclusively on live, publicly reachable
WordPress and WooCommerce installations — never on a local or offline environment.
Testing specifically took place on a subdomain (not the root/apex domain), which
is relevant for the Biometric method: WebAuthn/FIDO2 scopes credentials to the Relying
Party ID actually serving the page, so behavior on a subdomain reflects real-world
multisite/staging-style setups rather than only the simplest single-root-domain 
case. This is stated here for accuracy, since local setups can hide issues (HTTPS,
real SMTP delivery, actual mobile authenticators, real domain scoping) that only
show up under real-world conditions.

#### External services

This plugin sends emails using WordPress’s native `wp_mail()` function: no data 
is transmitted to third parties for this feature.

The Biometric login method (WebAuthn/FIDO2) never sends any data to third parties:
the cryptographic verification happens entirely on your own server and the user’s
own device.

If you configure SMS delivery, the 6-digit login code and your site name are sent
to **your own Twilio or Clickatell account** (whichever you choose) each time a 
user with SMS as their method and a saved phone number logs in. Message delivery,
retention, and pricing are governed by the provider you choose — see [Twilio’s privacy policy](https://www.twilio.com/en-us/legal/privacy)
or [Clickatell’s privacy policy](https://www.clickatell.com/help-center/policy-terms-and-conditions/what-is-your-policy-on-user-information-and-privacy/).

## Screenshots

[⌊Control panel — general settings⌉⌊Control panel — general settings⌉[

Control panel — general settings

[⌊Control panel — email and SMS configuration⌉⌊Control panel — email and SMS configuration⌉[

Control panel — email and SMS configuration

[⌊Control panel — biometric login (WebAuthn) setup⌉⌊Control panel — biometric login(
WebAuthn) setup⌉[

Control panel — biometric login (WebAuthn) setup

[⌊Control panel — security and emergency access options⌉⌊Control panel — security
and emergency access options⌉[

Control panel — security and emergency access options

[⌊Verification page — the code is filled in automatically from the email; the user
confirms with one click (backup codes also accepted)⌉⌊Verification page — the code
is filled in automatically from the email; the user confirms with one click (backup
codes also accepted)⌉[

Verification page — the code is filled in automatically from the email; the user
confirms with one click (backup codes also accepted)

[⌊Login code email — large, easy-to-read code with an "Enter the code automatically"
button⌉⌊Login code email — large, easy-to-read code with an "Enter the code automatically"
button⌉[

Login code email — large, easy-to-read code with an “Enter the code automatically”
button

## FAQ

### The login code never arrives by email. What can I do?

SPIDY uses WordPress’s own `wp_mail()`. If your server can’t deliver email (common
on self-hosted servers or residential connections), configure an SMTP plugin that
sends through your mail provider. Meanwhile, users can sign in with one of their
backup codes (Your Profile > Backup codes). To see the exact delivery error, add`
define( 'SPIDY_WP_DEBUG', true );` to wp-config.php and check the plugin’s debug.
log.

### I’m locked out of my own site. How do I get back in?

Add `define( 'SPIDY_2FA_OFF', true );` to wp-config.php (via FTP or your hosting
file manager), log in normally, fix the issue, then remove the line. A red notice
in the dashboard reminds you while 2FA is switched off.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“SPIDY 2FA LOGIN” is open source software. The following people have contributed
to this plugin.

Contributors

 *   [ carlocozzetto ](https://profiles.wordpress.org/carlocozzetto/)

[Translate “SPIDY 2FA LOGIN” into your language.](https://translate.wordpress.org/projects/wp-plugins/spidy-2fa-login)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/spidy-2fa-login/), 
check out the [SVN repository](https://plugins.svn.wordpress.org/spidy-2fa-login/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/spidy-2fa-login/)
by [RSS](https://plugins.trac.wordpress.org/log/spidy-2fa-login/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 2.0.3

 * Docs: added screenshots of the verification page and of the login code email.

#### 2.0.2

 * Tested with WordPress 7.1.

#### 2.0.1

 * Changed: the login code email is now HTML, with the code shown large and bold,
   plus an “Enter the code automatically” button that opens the verification page
   with the code already filled in (the user still confirms with one click, so link
   scanners can’t consume it). A plain-text version is included for mail clients
   without HTML.
 * Added: on the verification page, the form submits by itself as soon as 6 digits
   are typed or pasted, and a “Paste code” button reads the code from the clipboard
   where the browser allows it. The field is larger and easier to read.

#### 2.0.0

 * Added: one-time backup codes. From Your Profile, each user can generate 10 printable
   codes (format XXXX-XXXX); each one can be used once instead of the email/SMS 
   code. Codes are stored hashed and a new set replaces the previous one. They share
   the same 5-attempt limit as regular codes.
 * Added: `SPIDY_2FA_OFF` emergency switch in wp-config.php, a clearer name for 
   the existing `SPIDY_WP_BYPASS_BIOMETRIC` (which keeps working). While either 
   is active, administrators see a red dashboard notice.
 * Changed: when the email with the code can’t be sent and the user has backup codes,
   the verification page now says so and asks for a backup code, instead of skipping
   the second factor. Without backup codes, the previous behaviour (no lockout) 
   is unchanged. Same logic applies when both SMS and the email fallback fail.
 * Changed: the verification field now also accepts backup codes, with a short hint
   below it.
 * Added: “Code email sender” setting (sender address, sender name and Reply-To)
   for the emails carrying login codes — useful with SMTP plugins that route each
   sender address through its own mailbox.
 * Added: `wp_mail()` delivery errors are written to the plugin log, to help diagnose
   why codes aren’t arriving.
 * Security: the plugin’s `debug.log` (inside the plugin folder, reachable from 
   the web) was always written and could contain usernames and user IDs. It is now
   written only when `SPIDY_WP_DEBUG` is set to true in wp-config.php.
 * Uninstall with “delete all data” now also removes backup codes.

#### 1.6.12

 * SECURITY FIX: the login interception hooked into `wp_authenticate_user`, a WordPress
   core filter that fires _before_ the password itself is checked (`wp_check_password()`
   runs afterwards, inside `wp_authenticate_username_password()`). Combined with
   the redirect-and-`exit()` used to send the user to the 2FA verification page,
   this meant the second factor — and the OTP email/SMS send that goes with it —
   could be triggered by a valid username alone, with any password, since the password
   was never actually checked in that request. Not a full authentication bypass (
   the real OTP code, or a registered biometric device, is still required to finish
   signing in), but it allowed username enumeration and could be abused to trigger
   unwanted OTP emails/SMS at will (a direct cost where a paid SMS gateway is configured).
   Fixed by moving to the `authenticate` filter at priority 30 (after WordPress’s
   own core password checks, which run at priority 20), so the code guarantees `
   $user` is only ever a real `WP_User` when both username and password have already
   been verified successfully — matching the fix already applied on a different 
   branch of this plugin, ported back here.
 * Fixed: leftover `Domain Path: /languages` header pointing to a folder that isn’t
   bundled with the plugin (already listed as fixed in the 1.6.1 changelog entry
   below, but still present in this build).
 * Verified compatibility with WordPress 7.0.4 (security-only release for Imagick,
   unrelated to this plugin’s code) — full login flow (email, SMS, biometric) re-
   tested after updating.

#### 1.6.11

 * Fixed: the plugin header still listed “Web, Data & Service” as Author, inconsistent
   with the “carlocozzetto” account actually used for the WordPress.org repository(
   readme.txt Contributors was already correct). Also removed the same outdated 
   reference from the visible text on the plugin’s admin page

#### 1.6.10

 * Fixed: the “select/deselect all” toggle and its label in the 2FA column header
   made the table look cramped and unbalanced, since the row spacing no longer had
   a per-row Save button to fill it out. Shortened to “Attiva 2FA”, set fixed column
   widths, and centered the 2FA checkbox for a cleaner layout

#### 1.6.9

 * Changed: the user management table now saves all users in a single action (“Salva
   tutti”) instead of one save button per row — edit as many users as you need, 
   then save once
 * Added: a “select/deselect all” toggle on the 2FA column header, to enable or 
   disable two-factor authentication for every user at once before saving

#### 1.6.8

 * Improved: on smartphones with a built-in biometric sensor, the “Scan this QR 
   code with your phone” section is no longer shown during Biometric login — it 
   made no sense to ask users to photograph the very screen they were reading. The
   QR section still appears normally on desktop/PC, where it’s meant to be used.
   Detection is intentionally conservative (requires both a working platform authenticator
   and a mobile-device signal), so laptops with Windows Hello or similar are unaffected.
 * Changed: the “Verifica su questo dispositivo” button label was shortened to “
   Verifica ora” for consistency with the QR-page button, which already used the
   shorter wording.
 * Fixed: the internal `SPIDY_WP_VERSION` constant (used for cache-busting of CSS/
   JS assets) was still hardcoded to 1.6.0 while the plugin header had advanced 
   through several releases; now kept in sync with the plugin version.

#### 1.6.7

 * Removed the bundled `languages/` folder (translation files are managed by translate.
   wordpress.org, not shipped in the plugin package) — per WordPress.org Plugins
   Team review feedback.
 * Removed unneeded development-only folders bundled inside `vendor/` (PHPUnit test
   helpers, Symfony contract test base classes) that don’t belong in a production
   release.
 * Fixed a dead link to Clickatell’s privacy policy in the “External services” section.
 * Re-verified nonce and capability checks across every AJAX endpoint (already in
   place; no code change needed here).
 * Updated the bundled web-auth/webauthn-framework library from 4.9.3 to 5.3.5 (
   flagged as out of date in review) — no changes needed in our own code, which 
   already used the modern serializer-based API that carries over unchanged in 5.
   x.

#### 1.6.6

 * Fixed: the plugin declared “Requires PHP: 8.2” as a hard activation requirement,
   even though only the Biometric method actually needs it — WordPress would refuse
   to activate the plugin at all on lower PHP versions, making the built-in graceful-
   degradation logic (Email/SMS still work below 8.2) unreachable. Corrected to “
   Requires PHP: 7.4”; the runtime check that hides Biometric on PHP < 8.2 is unchanged.
 * Clarified in the readme that testing took place on a subdomain rather than a 
   root domain, which is relevant to the Biometric method’s WebAuthn Relying Party
   ID scoping.

#### 1.6.5

 * Fixed: device registration forced `authenticatorAttachment: 'platform'`, requiring
   the browser to use ONLY the device’s built-in biometric sensor (Windows Hello/
   Touch ID/Face ID) — on a computer where it isn’t set up, this surfaced as an 
   OS-level “Turn on Windows Hello” prompt with no way to proceed otherwise. Removed
   the restriction: the browser now offers every available option (built-in sensor,
   USB security key, browser-synced passkey, phone via QR/Bluetooth), and the user
   picks whichever they actually have.

#### 1.6.4

 * Fixed: biometric device registration reported “Operazione annullata” even after
   a successful Windows Hello/Face ID ceremony. Cause: `window.prompt()` asking 
   for a device name was called right after the async WebAuthn ceremony, and modern
   browsers (Chrome/Edge) block or auto-dismiss native dialogs in that situation,
   since the “user gesture” is considered already consumed. Replaced with an inline
   on-page input, which isn’t subject to this restriction.

#### 1.6.3

 * Fixed: “Tested up to” was rejected for including a patch number (7.0.2); WordPress.
   org only accepts major.minor here, corrected to 7.0.
 * Fixed: last remaining NonceVerification warning, a read-only check used only 
   to add a CSS body class.

#### 1.6.2

 * Added: `languages/` folder with a complete English translation (134 strings) 
   and the Italian source identity file, matching the current v1.6.2 codebase — 
   the source strings inside the plugin remain Italian, but English is now the fallback
   for anyone whose site language isn’t Italian, as required for WordPress.org submission.
 * Fixed: “Tested up to” corrected to 7.0.2, the current WordPress patch release.

#### 1.6.1

 * Fixed: “Tested up to” header referenced a non-existent WordPress version; corrected
   to the current stable release.
 * Fixed: removed the “Domain Path” header, which pointed to a non-existent `/languages`
   folder (no `.mo`/`.po` files were bundled). Corrected the description accordingly—
   the plugin is translation-ready, not yet pre-translated.
 * Fixed: unsanitized `$_POST['transports']` value during WebAuthn credential registration;
   now sanitized before decoding and filtered against the list of valid WebAuthn
   transport values.
 * Fixed: `wp_login` core hook manually fired after 2FA verification was flagged
   as an unprefixed custom hook; documented with an inline justification (it is 
   WordPress’s own hook, not a custom one).
 * Fixed: local template variables not prefixed with the plugin’s namespace.

#### 1.6.0

 * Complete rebuild starting directly from the last known-working biometric build,
   instead of layering changes on top of a separate codebase. Same three methods(
   Email / SMS / Biometric), SMS now via Twilio/Clickatell instead of SMSGate.
 * Fixed: assertion verification during login always passed a null user handle to
   the WebAuthn library instead of the expected fallback, causing verification to
   fail for authenticators that don’t send their own userHandle (e.g. Samsung Pass/
   Chrome on Android).
 * Fixed: several time-limited values (pending login token, OTP code, attempt counter,
   WebAuthn challenges) were stored using either native WordPress transients (unreliable
   on this hosting) or option keys that could exceed the historical 64-character
   limit of the wp_options.option_name column. All of these now use the same short,
   hashed, direct-write storage.
 * Fixed: HTTPS requirement no longer deactivates the entire plugin — only the Biometric
   method is affected; Email and SMS keep working over plain HTTP.
 * Added PHP-version guard: on PHP below 8.2, the WebAuthn library is not loaded
   at all (would fatal-error), and only the Biometric method is hidden — Email and
   SMS are unaffected.
 * Added an explicit “delete all data on uninstall” preference, honoured only when
   the plugin is deactivated and then deleted from the Plugins screen (never on 
   a simple update).

## Meta

 *  Version **2.0.3**
 *  Last updated **1 week ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.0 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 7.4 or higher **
 *  Language
 * [English (US)](https://wordpress.org/plugins/spidy-2fa-login/)
 * Tags
 * [2FA](https://lmo.wordpress.org/plugins/tags/2fa/)[login security](https://lmo.wordpress.org/plugins/tags/login-security/)
   [otp](https://lmo.wordpress.org/plugins/tags/otp/)[SMS Authentication](https://lmo.wordpress.org/plugins/tags/sms-authentication/)
   [two factor authentication](https://lmo.wordpress.org/plugins/tags/two-factor-authentication/)
 *  [Advanced View](https://lmo.wordpress.org/plugins/spidy-2fa-login/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/spidy-2fa-login/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/spidy-2fa-login/reviews/)

## Contributors

 *   [ carlocozzetto ](https://profiles.wordpress.org/carlocozzetto/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/spidy-2fa-login/)