From 43f511679ae27bb0bb6d93d672e8f560635c13d1 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Tue, 22 Sep 2026 18:26:15 +0530 Subject: [PATCH 1/3] fix: show error page when Auth0 returns a login error When Auth0 returns ?error= on the login callback, the plugin was silently redirecting to /. Reads error_description alongside error, fires a new auth0_login_failed hook, and calls wp_die() with a fixed generic message. Same treatment for onExchangeFailed() which also silently redirected. Default handler shows a fixed message rather than request-supplied values - both parameters are attacker-controllable (reflected content injection). Hook passes sanitized $error and $errorDescription for custom handlers. --- src/Actions/Authentication.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Actions/Authentication.php b/src/Actions/Authentication.php index bdb265a3..b815302f 100644 --- a/src/Actions/Authentication.php +++ b/src/Actions/Authentication.php @@ -41,6 +41,7 @@ final class Authentication extends Base 'login_form_logout' => 'onLogout', 'auth0_logout' => 'onLogout', + 'auth0_login_failed' => ['onLoginFailed', 2], 'auth0_token_exchange_failed' => 'onExchangeFailed', 'before_signup_header' => 'onRegistration', @@ -482,10 +483,13 @@ public function onLogin(): void $state = $this->getSdk()->getRequestParameter('state'); $exchangeParameters = null !== $code && null !== $state; - // Check if authentication flow error parameter is present (?error) + // Check if authentication flow error parameters are present (?error, ?error_description) $error = $this->getSdk() ->getRequestParameter('error'); + $errorDescription = $this->getSdk() + ->getRequestParameter('error_description'); + // Are token exchange parameters present? if ($exchangeParameters) { try { @@ -543,8 +547,9 @@ public function onLogin(): void } if (null !== $error) { - wp_redirect('/'); - exit; + error_log('Auth0 login error: ' . $error . ' - ' . ($errorDescription ?? '')); + do_action('auth0_login_failed', $error, $errorDescription ?? ''); + return; } if ($exchangeParameters && null === $error && (0 !== wp_get_current_user()->ID || null !== $this->getSdk()->getCredentials())) { @@ -556,11 +561,14 @@ public function onLogin(): void exit; } - public function onExchangeFailed(Throwable $_) + public function onLoginFailed(string $error, string $errorDescription): void { - // Custom hook ('auth0_token_exchange_failed') to register when token exchange fails. - wp_redirect('/'); - exit; + wp_die('There was a problem with your log in.', 'Login Error', ['response' => 200]); + } + + public function onExchangeFailed(Throwable $_): void + { + wp_die('There was a problem completing your sign-in.', 'Login Error', ['response' => 200]); } public function onLogout(): never From 961126a4dd12657e757fe64f72888f816bee1f36 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Thu, 24 Sep 2026 00:00:09 +0530 Subject: [PATCH 2/3] docs: note authentication error behavior change in upgrade guide --- UPGRADING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UPGRADING.md b/UPGRADING.md index ca4969a0..24f4ba43 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -16,7 +16,9 @@ Check that your environment is compatible with 6.0's requirements before upgradi Update your customizations, if necessary: -- **No changes are required for the plugin's built-in features.** Login, logout, the callback handler, and user session handling continue to work as they did in 5.x. The settings stored in the WordPress admin are unchanged. +- **No changes are required for the plugin's built-in features.** Login, logout, the callback handler, and user session handling continue to work as they did in 5.x. The settings stored in the WordPress admin are unchanged. See the authentication error behavior change below. + +- **Authentication errors now show an error page instead of silently redirecting to the homepage.** In 5.x, when Auth0 returned a login error on the callback (`?error=access_denied`, blocked account, breached-password policy, Login Action denial, etc.) or the OAuth token exchange threw an exception, the plugin redirected silently to `/` with no message shown. In 6.x, both paths render a generic error page via `wp_die()`. If your site needs to restore the silent redirect or show a custom message, hook into `auth0_login_failed` (for login errors) or remove and replace the default `auth0_token_exchange_failed` handler. - **User Sync now retries a failed event instead of always discarding it.** In 5.x a sync event that failed at the Management API was dropped from the queue regardless of the reason. In 6.x, a transient failure (an HTTP 429 rate limit, a 5xx server error, or a network error) keeps the event in the queue so the next cron pass retries it. Permanent failures (such as an HTTP 400 from an invalid profile) are still dropped, since retrying them would never succeed. No configuration change is needed, but a queue that previously drained to empty on every pass may now hold a retrying event until it succeeds. - **Custom code that calls the Management API has changed.** In v9 the old `wpAuth0()->getSdk()->management()` entry point is non-functional and will throw a `TypeError`. Use the new `wpAuth0()->getManagement()` accessor instead. It builds a Management client from the Domain, Client ID, and Client Secret you already configure in the plugin settings, and fetches and caches a client credentials token for you automatically. From 5f18e9372675cea971d337a88523c438ad139d52 Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Thu, 24 Sep 2026 00:25:05 +0530 Subject: [PATCH 3/3] fix: address review feedback on login error handling - Strip CR/LF from error and description before error_log to prevent log line injection - Prefix unused onLoginFailed params with _ to satisfy static analysis - Unify error message wording between onLoginFailed and onExchangeFailed - Extend registry to support optional priority in [method, args, priority] format - Register onLoginFailed at priority 20 so custom handlers at the default priority 10 run first --- src/Actions/Authentication.php | 10 +++++----- src/Actions/Base.php | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Actions/Authentication.php b/src/Actions/Authentication.php index a4632d0e..a797e8ec 100644 --- a/src/Actions/Authentication.php +++ b/src/Actions/Authentication.php @@ -41,7 +41,7 @@ final class Authentication extends Base 'login_form_logout' => 'onLogout', 'auth0_logout' => 'onLogout', - 'auth0_login_failed' => ['onLoginFailed', 2], + 'auth0_login_failed' => ['onLoginFailed', 2, 20], 'auth0_token_exchange_failed' => 'onExchangeFailed', 'before_signup_header' => 'onRegistration', @@ -560,7 +560,7 @@ public function onLogin(): void } if (null !== $error) { - error_log('Auth0 login error: ' . $error . ' - ' . ($errorDescription ?? '')); + error_log('Auth0 login error: ' . str_replace(["\r", "\n"], ' ', $error) . ' - ' . str_replace(["\r", "\n"], ' ', $errorDescription ?? '')); do_action('auth0_login_failed', $error, $errorDescription ?? ''); return; } @@ -589,14 +589,14 @@ public function onLogin(): void exit; } - public function onLoginFailed(string $error, string $errorDescription): void + public function onLoginFailed(string $_error, string $_errorDescription): void { - wp_die('There was a problem with your log in.', 'Login Error', ['response' => 200]); + wp_die('There was a problem signing in.', 'Login Error', ['response' => 200]); } public function onExchangeFailed(Throwable $_): void { - wp_die('There was a problem completing your sign-in.', 'Login Error', ['response' => 200]); + wp_die('There was a problem completing your sign in.', 'Login Error', ['response' => 200]); } public function onLogout(): never diff --git a/src/Actions/Base.php b/src/Actions/Base.php index b2aa7997..bbde4522 100644 --- a/src/Actions/Base.php +++ b/src/Actions/Base.php @@ -30,6 +30,7 @@ final public function addAction(string $event, $method = null): ?Hooks $callback = null; $method ??= $this->registry[$event] ?? null; $arguments = 1; + $priority = $this->getPriority($event); if (null !== $method) { if (is_string($method)) { @@ -39,11 +40,14 @@ final public function addAction(string $event, $method = null): ?Hooks if (is_array($method) && count($method) >= 1 && is_string($method[0]) && is_numeric($method[1])) { $callback = $method[0]; $arguments = (int) $method[1]; + if (isset($method[2]) && is_numeric($method[2])) { + $priority = (int) $method[2]; + } } if (null !== $callback) { return $this->plugin->actions() - ->add($event, $this, $callback, $this->getPriority($event), $arguments); + ->add($event, $this, $callback, $priority, $arguments); } } @@ -106,6 +110,7 @@ final public function removeAction(string $event, $method = null): ?Hooks $callback = null; $method ??= $this->registry[$event] ?? null; $arguments = 1; + $priority = $this->getPriority($event); if (null !== $method) { if (is_string($method)) { @@ -115,11 +120,14 @@ final public function removeAction(string $event, $method = null): ?Hooks if (is_array($method) && count($method) >= 1 && is_string($method[0]) && is_numeric($method[1])) { $callback = $method[0]; $arguments = (int) $method[1]; + if (isset($method[2]) && is_numeric($method[2])) { + $priority = (int) $method[2]; + } } if (null !== $callback) { return $this->plugin->actions() - ->remove($event, $this, $callback, $this->getPriority($event), $arguments); + ->remove($event, $this, $callback, $priority, $arguments); } }