MagicAuth
Changelog
Version history for MagicAuth.
1.4.0
- UI: full admin design system rewrite. New dark navy topbar with brand mark, version pill, live unsaved-changes counter (amber pulse, then green check when saved), and Save/Discard buttons that auto-disable when there is nothing to save. Section blocks with strong h2 headings outside cards, white card surfaces with quiet 1px borders, and component-styled controls (toggles, segmented control, role chips, fused color picker, char counters, live hex validation, native color input).
- UX: per-row dirty mark. Small amber dot to the immediate left of any control adjusted-but-not-saved. Clears on Save or Discard.
- UX: replaced
window.confirm()for destructive actions with a designed confirm modal (backdrop blur, danger variant for Revoke). Both modal confirm and form Save show inline loading state (spinner plus label swap) while the action runs. Success/error result surfaces as a bottom-right toast. - UX:
settings_errors()now render as styled inline notices (info/success/warn/error variants) with a dismiss button instead of WP's default coloured-bar admin notices. - UX: disabled-with-reason tooltip. When "Replace WordPress login screen" is locked because
wp-config.phphas placeholder salts, an info pill next to the label explains why and links to the salt generator. - Internal: dropped jQuery and
wp-color-pickerdependencies from the admin script. Vanilla JS, native colour input. - Internal: rendering layer in
Settings.phprewritten to emit the design system markup. Security-criticalregister_setting()andsanitize()callback unchanged. AJAX endpoints, the test-email admin-post flow, and all option key names preserved. Existing settings carry over without migration.
1.3.7
- Fix: "Reset throttle counters" recovery button now works on hosts with an external object cache (Redis, Memcached, Object Cache Pro). The previous
wp_optionsLIKE scan returned zero rows under Redis, so the button silently no-op'd. v1.3.7 maintains a key registry per request and enumerates the registry on flush. Thewp_optionsscan stays as defence-in-depth for pre-1.3.7 transients still in the database. Fires a newmagicauth_throttle_keys_flushedaction. - Security: per-email throttle redesigned. The old hard cap (3 requests / 15 minutes) was a denial-of-service primitive. Any IP could lock out any victim email by hammering it 4 times every 15 minutes. v1.3.7 replaces it with a 60-second cooldown (configurable 0 to 600s, 0 disables). The first request always goes through, a second within the cooldown window is denied, and the cooldown does not extend on retry. Aligns with OWASP, Auth0, MojoAuth, and SuperTokens guidance.
- UX: throttle-block toasts. When a visitor hits any throttle, the front-end now shows a clear amber warning toast naming the block reason instead of the silent generic envelope. Per-email cooldown also passes a remaining-seconds value so the toast counts the user down accurately.
1.3.5
- Feature: new "Diagnostics & Recovery" section under Settings → MagicAuth with two admin recovery actions:
- Revoke all magic-links and codes. Site-wide single-click invalidation of every outstanding token. Live sessions are not signed out.
- Reset throttle counters. Clears every
magicauth_throttle_*transient. Useful when a probe has pinned the rate limit.
- Both actions are admin-only (
manage_options), CSRF-nonce gated, idempotent, and return inline success/failure feedback without a page reload.
1.3.4
- Security: throttle counter no longer pins indefinitely under sustained attack. Once the cap is crossed, further over-cap requests stop refreshing the TTL, so the bucket drains naturally (pentest finding R-1).
- Security: magic-link and disabled-notice emails now dispatch via
register_shutdown_functionandfastcgi_finish_requestsowp_mail's blocking SMTP latency stays off the HTTP response path. Closes a ~60ms timing oracle that allowed user enumeration with 30 to 50 statistically aggregated samples per email (pentest T-1, T-2). No wp-cron dependency. Falls back to synchronous send on non-PHP-FPM hosts. - Hardening: every plugin-rendered page (verify GET, branded login, lostpassword, reset-password) now emits
X-Content-Type-Options: nosniff. - Hygiene:
magicauth_offrecovery cookie is scoped to/wp-login.phpinstead of/, removing 10 minutes of cache-key noise on every other request.
1.3.3
- UX: every front-end error (wrong code, sign-in failed, password reset failed, expired link) now surfaces as a top-right toast with the same styling as the "Email sent" confirmation. Error toasts use
role="alert"andaria-live="assertive"so screen readers announce them assertively. - UX: error toasts linger for 10 seconds (success toasts stay at 4) so the visitor has time to read actionable recovery text before it fades.
1.3.1
- Style: agency-credit row renders as a transparent footer strip centred under the sign-in card instead of a second white card. Reads as attribution rather than competing with the login surface.
1.3.0
- Feature: colour mode setting (Light / Dark / Auto) for the sign-in screens.
- Feature: optional "Built by [Brand]" agency credit box below the sign-in card on customer-facing surfaces. Three fields (brand name, brand URL, brand favicon). All required for the credit to render.
- Feature: when a per-user-disabled account requests a sign-in code, that user receives a one-shot notification email explaining magic-link sign-in is turned off for their account. Throttled to one notice per 24 hours per email so the request form cannot be weaponised to flood a disabled user's inbox. The public UI envelope stays generic, with the same screen text and timing as every other miss path. Email contains zero clickable URLs.
1.2.1
- Fix: logo selection silently reverted on save. The validation array passed to
wp_check_filetype_and_ext()was keyedmimetoextwhen WordPress expectsexttomime. - Compat:
.svgattachments already in the media library can now be selected as a logo. We do not enable SVG uploads.
1.2.0
- Feature: new "Company name" setting in Branding. Sign-in emails (subject, From line, body), branded login screens, and logo alt text now use this name instead of the WordPress Site Title. Field is seeded from the Site Title on first install. Clearing it falls back to the Site Title at runtime.
- UX: email subject is now
XXX-XXX is your {Company}-codeso the verification code appears on lock-screen and inbox previews.
1.1.x
- 1.1.2: Style. Code placeholder format hint changed from "ABC-123" to "XXX - XXX" so the dash position matches a typed code.
- 1.1.1: Style. Heading and body text left-aligned across all states. Heading reduced from 36px to 26px. Password input now matches email/text input styling. Tighter vertical rhythm on the password card.
- 1.1.0: Feature. Full branded password fallback. The "Sign in with password" link reveals a password field inside the MagicAuth shell instead of bouncing to native
wp-login.php. New states C (password entry), D (lost-password request), E (set new password from reset email). Branded?action=lostpassword,?action=rp, and?action=resetpassscreens. Dedicated per-IP throttle buckets for password-submit (5 / 15 min) and password-reset (5 / 60 min). Password-submit failures firewp_login_failed. Lost-password POST always emits the same opaque envelope.
1.0.x
- 1.0.9: Fix. Invalid, expired, or already-used sign-in link clicks now redirect to the MagicAuth login page with an error toast instead of an unstyled message inside the active theme.
- 1.0.8: Fix. State-B (code entry) error showed the state-A enumeration-envelope text. Replaced with a context-appropriate message.
- 1.0.7: Add. "Email sent. Check your mail app." toast on every state-A to state-B transition.
- 1.0.6: Design. Vertical-centred card. Tighter corner radius. "Send Link" button gated by a valid email. Centred code-input placeholder.
- 1.0.5: Fix. Branded-login heading rendered blank because of an overzealous hide rule. Filter
magicauth_login_headingnow receives($default, $state, $brand, $site_name). - 1.0.4: Design. Branded login screen rebuilt to match the Gravatar-style reference. Logo moved into the card. Heading defaults to a short "Sign in" or "Check your email".
- 1.0.3: Fix. Typed-code sign-in bounced back on hosts where the
magicauth_sessioncookie did not survive the round-trip (caching, CDN-stripped Set-Cookie,COOKIEPATHmismatches). Session id now also propagates via URL handoff and a hidden form field. - 1.0.2: Fix. Typed-code sign-in succeeded server-side but bounced the user back to the login form. Authenticated visitors now redirect to admin/home.
wp-login.phpis rejected as a post-login destination. - 1.0.1: Fix. Branded login screen rendered an empty card on
wp-login.php?action=magicauth. Hide rule now targets WordPress's default elements by ID. - 1.0.0: Initial release.