Use wp_login_url() instead of hardcoded site_url(‘/wp-login.php’) for the two locations that reference the W login URL. This respects security plugins that move wp-login.php to a custom URL and is the recommended pattern per the WordPress developer handbook.
0.1.20
Compliance: vendored the TypeScript source for the bundled @qrauth/web-components library at assets/js/source/ alongside the minified bundle, so reviewers and integrators can read the unminified source without leaving the plugin. The readme’s == Source == section (renamed from == External resources == for clarity) and the Description’s “Open source build” paragraph also link to the canonical upstream repository and build instructions. WordPress.org plugin guideline 4 (human-readable code).
0.1.19
Account safety: the qrauth_psl_provisioning_role filter introduced in 0.1.16 has been removed. Auto-provisioned users are now hardcoded to the subscriber role at every layer — settings UI, sanitiser, and runtime provisioner — with no programmatic path (filter, action, option, or constant) to elevate. Operators who need a different role for an individual user must update it manually via Users → All Users after first sign-in. Identified during WordPress.org plugin directory review (creating users post-external-verification must be capped at the lowest privilege role).
0.1.18
Security ecosystem compatibility: the /verify route now fires the canonical wp_login action on every successful sign-in (mirroring what core’s wp_signon() does after wp_set_auth_cookie()) and wp_login_failed on signature_invalid rejections. Security plugins (Limit Login Attempts Reloaded, Wordfence, Solid Security), audit-log plugins (WP Activity Log, Simple History), MFA gates, and “last login” / session-tracking plugins now see QRAuth sign-ins exactly as if the user had authenticated through wp-login.php. Identified during WordPress.org plugin directory review — closes the “creating your own login method can bypass security plugins” concern raised in the review. No configuration changes required.
Documentation: added an == External resources == section to the readme that publishes the plugin’s own GitHub repository (https://github.com/qrauth-io/qrauth-passwordless-social-login, GPL-2.0-or-later) and points at the public source for the vendored @qrauth/web-components library (https://github.com/qrauth-io/qrauth/tree/main/packages/web-components, MIT) along with the npm release the bundle is pinned to and the npm run build:assets step that reproduces it. The vendored file’s banner now names its source repository, license, npm release, and build entry-point inline. The plugin header’s Plugin URI: now points at the GitHub repository instead of the QRAuth platform homepage, and a top-level LICENSE file (GPL-2.0) has been added to the repository so forkers and reviewers see the licence at a glance. Addresses WordPress.org plugin directory feedback that compiled JS must link to a publicly maintained, human-readable source.
0.1.17
Fixed: same-device mobile sign-in’s “Continue with QRAuth” URL no longer drops its query string when proxying to the QRAuth tenant. Without this, the signal that distinguishes same-device clicks from cross-device QR scans was being stripped at the WordPress proxy layer, so the hosted approval page could no longer decide reliably whether to redirect after approval — sites with a strict Referrer-Policy could end up landing the user on a “you can close this page” terminal state instead of returning them to wp-login.php. The /a/<token> proxy now forwards the query string verbatim, matching the existing behaviour documented for the /api/v1/auth-sessions/<id> proxy.
0.1.16
Security: bumped vendored QRAuth web component to 0.4.1, which renders QR codes locally instead of fetching them from a third-party image service (api.qrserver.com). No more outbound calls leave the visitor’s browser to hosts other than your own site. Identified during WordPress.org plugin review.
Privacy: the readme now carries an explicit == External services == section documenting every outbound call the plugin makes, with links to the QRAuth Terms, Privacy Policy, DPA, and Sub-processors list.
Account safety: the auto-provisioning UI now offers only “Subscriber” — Contributor and Author have moved behind the new qrauth_psl_provisioning_role filter, accessible only via code. Editor and Administrator remain hard-blocked at every layer, as before. Existing sites configured with Contributor or Author will fall back to Subscriber on the next save; until then their stored value is unchanged.
0.1.15
Author URI: https://github.com/aristech
0.1.14
Readme: Contributors: field set to aristech — the verified wordpress.org account that owns the submission. The prior value (qrauth) wasn’t a registered wordpress.org profile and would have rendered as a broken contributor badge on the plugin directory page.
0.1.13
Security (low-severity hardening): the Tenant URL sanitiser now rejects http://localhost and http://127.0.0.1 values on production sites — they’re only accepted when WP_DEBUG is on (local development) or when a site operator explicitly opts in via the new qrauth_psl_allow_localhost_tenant_url filter. Closes a pentest finding: an admin with manage_options could previously point Tenant URL at arbitrary localhost ports (e.g. MySQL, Redis), using the plugin’s outbound wp_remote_request as a port-scanning oracle against the WP host’s internal network. Now admin-gated SSRF via this path is blocked by default; https:// tenants remain accepted unchanged.
0.1.12
CI/release infrastructure: bumped all GitHub Actions flagged by the Node-20 deprecation warning (actions/checkout, actions/setup-node, softprops/action-gh-release, actions/upload-artifact, ramsey/composer-install) to current major versions so every runner step uses Node.js 24. No plugin behaviour changes — only the CI environment that builds + releases the plugin changed.
0.1.11
Fixed: three plugin-check warnings surfaced while preparing the WordPress.org submission. (1) The release ZIP now includes composer.json alongside vendor/ so reviewers can see the provenance of the vendored dependencies. (2) Removed the explicit load_plugin_textdomain() call from plugin bootstrap — WordPress 4.6+ auto-loads translations for plugins hosted on wordpress.org, and an explicit call is now discouraged. (3) Trimmed the 0.1.8 upgrade notice to stay under WordPress.org’s 300-character limit.
0.1.10
i18n: regenerated the translation template (languages/qrauth-passwordless-social-login.pot) and the Greek scaffold (el_GR.po) so every user-facing string added between 0.1.1 and 0.1.9 (Client Secret field, Tenant URL description, per-surface enable switches for shortcode and WooCommerce, mobile sign-in setup callout, etc.) is now available to translators. No behaviour changes; string extraction only.
0.1.9
Changed: after a successful sign-in, customers on WooCommerce surfaces now land on their My Account page (or the checkout step, if that’s where they started) instead of wp-admin. Sign-ins from wp-login.php still go to wp-admin. Sign-ins from a custom page (shortcode) go back to that page. Decided server-side from the request’s Referer, validated same-origin via WordPress core’s wp_validate_redirect so a forged Referer can’t turn this into an open redirect.
0.1.8
Fixed: cross-device QR scan no longer inadvertently signs in the scanning device. Previously, a phone that scanned a desktop-initiated QR and approved on qrauth.io would get redirected back to wp-login.php and auto-sign-in, because the landing-page adapter couldn’t distinguish “this browser initiated the session” from “this browser just happens to be visiting the redirect URL”. The proxy now stamps a short-lived, browser-scoped cookie at session-create time, and the adapter only auto-completes sign-in when that cookie matches the sessionId in the URL — same-device mobile flow unaffected, cross-device leaves the scanning device on the login page.
Fixed: multilingual sites using WPML / Polylang / Weglot no longer need a separate redirect-URL registered per language. The widget now emits its redirect-uri using WordPress’s language-neutral admin URL (site_url) instead of the translated home URL, so /en/wp-login.php, /fr/wp-login.php, etc. all resolve to the same canonical registration in the QRAuth dashboard.
0.1.7
Added: WooCommerce integration. When WooCommerce is active, Settings → QRAuth shows two new checkboxes — “WooCommerce My Account + checkout login” (covers /my-account/ and the checkout page’s returning-customer sign-in) and “WooCommerce registration form”. The widget appears inside WooCommerce’s own forms via the standard woocommerce_login_form_end / woocommerce_register_form_end template hooks.
Settings checkboxes are hidden on non-WooCommerce sites — the plugin stays clean on simple blogs.
0.1.6
Added: [qrauth_login] shortcode for placing the widget on any page, post, or widget area. Supports display=”inline|button” (default inline) and mode=”login|register” (default login). Opt in via Settings → QRAuth → “Show widget on” → “Anywhere via shortcode”.
Widget asset loading now runs on front-end pages when the shortcode is used, not just on wp-login.php. The ~65 KB bundle is only emitted on pages that actually render the widget — unused shortcode-enabled sites pay zero bandwidth cost on pages without the tag.
0.1.5
Added: mobile same-device sign-in. The login widget now emits redirect-uri pointing at wp-login.php, and the adapter picks up the qrauth_session_id / qrauth_signature query params that qrauth.io appends when the user approves on their phone. The WP tab being suspended while the user was on qrauth.io no longer breaks the flow.
Added: Settings → QRAuth now shows the exact URL admins need to register in their QRAuth app’s redirect-URL allowlist (typically https://<site>/wp-login.php). Required one-time setup for phone sign-in; desktop still works without it.
0.1.4
Fixed: logins completed past /verify on 0.1.3 but bounced with provision_disabled — regardless of whether auto-provisioning was on. The widget’s scope attribute was emitted as scope (singular) while the QRAuth web component reads scopes (plural), so only the default identity scope was requested and /verify-result returned no email. Email-based account matching and new-user provisioning both rely on having the email, so both paths failed with the same error code. Restored the correct attribute name — no action required on upgrade.
0.1.3
Fixed: /verify still rejected real logins on 0.1.2 with rest_invalid_param because the signature value QRAuth returns is an envelope (<keyId>:<base64sig>), and the validator’s alphabet didn’t include the : separator. Added : and . to the accepted character set. No action required on upgrade.
0.1.2
Fixed: /verify rejected every real login with rest_invalid_param because the input validators were pinned to old formats. sessionId now accepts QRAuth’s current cuid format (not only UUIDs); signature now accepts standard base64 (with +, /, =) in addition to base64url. No action required on upgrade — auth on existing sites starts working again automatically.
0.1.1
Added a same-origin REST proxy (qrauth-psl/v1/api/v1/auth-sessions, …/a/<token>) so the login widget talks to your site’s own WordPress REST API. No more browser-level CORS errors on third-party hosts.
New Client Secret setting. Used server-side only to authenticate the proxy against qrauth.io. Never exposed to the browser.
Options rename: base_url → tenant_url. Existing configurations are migrated automatically on upgrade; no manual action required.
Tenant URL help text clarified for non-technical admins; a debug line showing the effective REST URL is now emitted only when WP_DEBUG is on.
Dropped the widget’s redirect-uri attribute — it was never used by the plugin and triggered exact-match allowlist rejections on qrauth.io.
0.1.0
Initial public release.
Passwordless sign-in on wp-login.php via the vendored QRAuth web component (v0.4.0).
Server-side cryptographic verification against QRAuth’s /verify-result endpoint with TLS + 10 s timeout.
Auto-provisioning (off by default) with role clamped to subscriber / contributor / author.
Per-user profile UI for unlinking QRAuth, preserving the WordPress account.
Uninstall cleanup that removes plugin options + transients but never touches wp_users or wp_usermeta.
REST route rate-limited at 10 requests per 5 minutes per hashed IP.
Full i18n scaffolding (POT + Greek translation source).