WP Manifestindependent plugin directory
manifest / users / rep-magic-login

REP Magic Login (Passwordless Email Link)

Passwordless WordPress login via one-time emailed magic links. Single-use, hashed, expiring tokens; intentionally bypasses 2FA by design.

by ACWebDev LLC · github.com/abchiaravalle/rep-magic-login

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/abchiaravalle/rep-magic-login/archive/refs/heads/main.zip

Readme

REP Magic Login (Passwordless Email Link)

A single-file WordPress plugin that lets users log in via a one-time, short-lived link emailed to their on-file address — no password required. Built for users who struggle with passwords.

How it works

  1. On wp-login.php, a user clicks "Can't use your password? Email me a login link".
  2. They enter their username or email. A 256-bit token is generated; only its SHA-256 hash is stored (update_user_meta). The raw token is emailed as a link to the account's on-file address — never to whatever address they type in the form.
  3. Clicking the link opens a small confirm page that auto-submits a POST to actually authenticate. The token is deleted from the database before validation (so it can never be replayed), then compared with hash_equals() (constant-time), then the user is logged in via wp_set_auth_cookie().
  4. The link works once and expires in 15 minutes.

Security design

  • 256-bit tokens, only SHA-256 hashes ever touch the database.
  • Single-use: the token record is deleted before validation, so replay is impossible even if the link leaks after use.
  • 15-minute expiry.
  • Two-step consume (GET renders, POST authenticates): the emailed link is a plain GET, but visiting it does not consume the token — it renders a page that auto-submits a POST. This exists specifically so automated email-security link scanners (Microsoft 365 Safe Links, Proofpoint, Mimecast, etc.), which prefetch links server-side before a human opens them, can't silently burn the token.
  • No user enumeration: the request-a-link response is identical (body and, as of v1.1.0, padded timing) whether or not the submitted username/email resolves to a real account.
  • Per-user AND per-IP rate limiting: 1 request/min per resolved account, plus an IP-level cap so guessing usernames that don't exist is still throttled.
  • CSRF protection via WordPress nonces on the request form.
  • Failed/expired/invalid token attempts fire wp_login_failed, so security plugins (Wordfence, etc.) can see and alert on them.
  • Administrators are excluded from magic login by default (filterable) — see the intentional trade-off below.

Intentional trade-off: this bypasses 2FA

Authentication happens via wp_set_current_user() / wp_set_auth_cookie() directly rather than through wp_signon()/wp_authenticate, which means any 2FA plugin's normal auth-chain hooks are not invoked. This is deliberate: for the target audience — people who struggle with passwords — possession of the emailed link is the second factor. If you need 2FA enforced even for magic-login users, don't enable this plugin for those accounts, or use the rep_magic_login_allowed_user filter to exclude them.

Filters

// Control which users may use magic login. Receives (bool $allowed, WP_User $user).
// Default: everyone except administrators.
add_filter( 'rep_magic_login_allowed_user', function( $allowed, $user ) {
    return $allowed;
}, 10, 2 );

// Control the post-login redirect. Receives (string $url, WP_User $user).
add_filter( 'rep_magic_login_redirect', function( $url, $user ) {
    return $url;
}, 10, 2 );

Requirements

  • WordPress with a working outbound mailer (e.g. WP Mail SMTP) — magic links are useless if wp_mail() can't actually deliver.
  • PHP random_bytes() (PHP 7+, built in).

Installation

Drop rep-magic-login.php into wp-content/plugins/rep-magic-login/ and activate it from the WordPress admin, or via WP-CLI:

wp plugin activate rep-magic-login

Known limitations

  • Corporate email link-scanners that execute JavaScript (rare, but exists) could still trigger the auto-submit on the confirm page. The two-step design blocks the common case (server-side prefetchers that fetch the URL without rendering/executing anything), not every conceivable scanner.
  • Timing-based padding on the "request a link" response reduces but does not perfectly eliminate a timing side-channel for enumeration on unusually slow mail infrastructure.
  • No built-in CAPTCHA/honeypot on the request form; the per-IP rate limit is the primary defense against automated abuse at volume.

License

GPL-2.0-or-later

Read the full README on GitHub →