Email is the lowest-overhead authenticator your users already have. SMS adds a paid third party, a phone-number PII surface, and a SIM-swap attack vector. We pass.
Drop-in passwordless sign-in for WordPress. Click on your laptop, type on your phone. Same token, atomically consumed, gone in ten minutes.
Sign in with password
Tested on the WordPress you already run, no SaaS or SDK in the loop
PHP 8.0+
Every sign-in email contains both a clickable magic link and a typeable 6-character code. Same 256-bit token, atomically consumed.
Click on your laptop. Type on your phone. The first one through wins, every other path returns the same uniform error envelope.
Default TTL is 10 minutes. Default code attempts is 5. Adjustable in WP admin or by filter.
Plaintext only ever lives in the URL or email. Only the HMAC-SHA-256 hash hits the database. Comparisons run with hash_equals().
A single SQL UPDATE serialises concurrent callers. Race-safe. The deferred mailer closes a measured 61ms timing oracle.
Unknown email, throttled, wrong code, expired link: all four take the same time to fail. 50 to 150ms jitter masks the rest.
Scope, not feature creep
Email is the lowest-overhead authenticator your users already have. SMS adds a paid third party, a phone-number PII surface, and a SIM-swap attack vector. We pass.
Same problem as SMS, plus a per-message cost. If your auth needs span more than email, you're shopping for an identity layer, not a plugin.
Pretty UX, but it's a magic link with extra steps. Use the link.
Google, Apple, GitHub: every one of those is its own consent screen, key rotation, and trust problem. WordPress already has a plugin for that.
MagicAuth signs people in. If they don't have an account yet, your existing onboarding handles that.
We rate-limit by IP, by email, and by a global per-site bucket. That's the bot answer that doesn't ship Google to your users.
Tokens, hashes, and audit logs live in your wp_ tables. No data leaves the box.
GPL-2.0. No usage tier. No "starter" with a banner ad. Install it on your client's site, mark it up however you bill. We're not in the loop.
Thirty public actions and filters cover every important moment: token issued, token consumed, email subject, redirect target, client IP source, login heading, cookie set.
Override email templates by dropping a copy into your-theme/magicauth/. Send via your own transport by short-circuiting magicauth_email_send.
Programmatic API: TokenManager::issue(), ::consume(), ::revoke(). Same code paths your wp-login screen uses.
// Issue a one-shot magic link from PHP use MagicAuth\Auth\TokenManager; $result = TokenManager::issue( $user_id, 'user@example.com' ); // $result['link_url'] // $result['code_plaintext'] // $result['selector'] // $result['expires_at'] // Route every email through your own transport add_filter('magicauth_email_send', function ($null, $args) { return $mailer->send($args); }, 10, 2);
Self-hosted, by default
MagicAuth ships as a single WordPress plugin. Tokens, hashes, audit logs, brand assets: all of it lives in your wp_ tables, on your servers, under your backup policy.
// In wp-config.php define('MAGICAUTH_PRESET', 'production'); define('MAGICAUTH_TTL_LINK', 600); define('MAGICAUTH_TTL_CODE', 600); define('MAGICAUTH_RATE_PER_IP', 5); define('MAGICAUTH_RATE_PER_EMAIL', 3); // Optional: override the default brand define('MAGICAUTH_BRAND_COLOR', '#0F5CFA'); // Optional: trust a specific reverse-proxy header define('MAGICAUTH_TRUSTED_IP_HEADER', 'CF-Connecting-IP'); /* Token, audit-log and rate-limit tables * are created on activation in: * wp_magicauth_tokens * wp_magicauth_log * wp_magicauth_throttle */
GPL-2.0. No accounts, no usage tier, no paid pro version.
All paths give you the same plugin. Pick the one that fits your stack.
For sites managed through wp-admin. Auto-updates handled by WordPress core.
For Bedrock and Sage stacks, with locked versions and CI-driven deploys.
For contributors, security researchers, and unreleased branches.
Activate the plugin, set a brand colour, and your wp-login.php becomes a passwordless sign-in screen. No SaaS, no SDK, no SMS provider.
The whole thing is one PHP plugin, around 3000 lines, sitting in your wp-content/plugins/. It reads like a piece of WordPress, because it is one.
If you can install a plugin, you've already finished the hard part.
Upload, activate, set a brand colour. Your wp-login is now passwordless.
wp plugin install magicauth --activate
If your users have email, they have access. The password tickets stop arriving.