From 22519d94e6d45e1521859d36b6d2027eb40dc73e Mon Sep 17 00:00:00 2001 From: Snehil Kishore Date: Sun, 14 Jun 2026 20:28:12 +0530 Subject: [PATCH] feat(deps): auth0-php v9 compatibility (6.x beta groundwork) --- .gitignore | 5 ++ README.md | 68 +++++++++++++++++---- UPGRADING.md | 48 +++++++++++++++ build.sh | 25 +++++++- composer.json | 6 +- scoper.inc.php | 62 +++++++++++++++++-- src/Actions/Base.php | 6 ++ src/Actions/Configuration.php | 18 +++--- src/Actions/Sync.php | 109 +++++++++++++++++++++------------- src/Plugin.php | 38 ++++++++++++ wpAuth0.php | 5 +- 11 files changed, 317 insertions(+), 73 deletions(-) create mode 100644 UPGRADING.md diff --git a/.gitignore b/.gitignore index 11f960d99..f8d0d4854 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,10 @@ private-signing-key.pem build.zip build.zip.sig +# build.sh output artifacts (renamed plugin folder + signed release zips) +wp-auth0 +Auth0_WordPress_*.zip +Auth0_WordPress_*.zip.sig + # AI tools .claude diff --git a/README.md b/README.md index d17b9d312..b8c2ba20d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ WordPress Plugin for [Auth0](https://auth0.com) Authentication [![License](https://img.shields.io/packagist/l/auth0/auth0-php)](https://doge.mit-license.org/) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/auth0/wordpress) -:rocket: [Getting Started](#getting-started) - :computer: [SDK Usage](#sdk-usage) - 📆 [Support Policy](#support-policy) - :speech_balloon: [Feedback](#feedback) +:rocket: [Getting Started](#getting-started) - :sparkles: [Features](#features) - :computer: [SDK Usage](#sdk-usage) - 📆 [Support Policy](#support-policy) - :speech_balloon: [Feedback](#feedback) ## Overview @@ -14,14 +14,14 @@ The Auth0 WordPress plugin replaces the standard WordPress login flow with a new > [!IMPORTANT] > This plugin is **NOT** a SDK (Software Development Kit.) It's APIs are internal and not intended for developers to extend directly. We do not support altering the plugin's behavior or integrating it in any way beyond what is outlined in this README. If you're looking to build a more extensive integration, please create a solution using the [Auth0-PHP SDK](https://github.com/auth0/auth0-php) instead. -> [!WARNING] -> v4 of the plugin is no longer supported as of June 2023. We are no longer providing new features or bugfixes for that release. Please upgrade to v5 as soon as possible. +> [!NOTE] +> Upgrading from 5.x? The 6.0 release moves the plugin onto [auth0-php v9](https://github.com/auth0/auth0-php/tree/v9) and raises the minimum PHP version to 8.2. The built-in features (login, logout, callback, sessions, and User Sync) work unchanged, but custom code that calls the Management API must move from `getSdk()->management()` to the new `getManagement()` accessor. See [UPGRADING.md](./UPGRADING.md) for details. ## Getting Started ### Requirements -- PHP 8.1+ +- PHP 8.2+ - [Most recent version of WordPress](https://wordpress.org/news/category/releases/) - Database credentials with table creation permissions @@ -62,7 +62,7 @@ For [Bedrock](https://roots.io/bedrock/) installations, you'll usually run this For standard WordPress installations, this command can be run from the `wp-content/plugins` sub-directory. ``` -composer require symfony/http-client nyholm/psr7 auth0/wordpress:^5.0 +composer require symfony/http-client nyholm/psr7 auth0/wordpress:^6.0 ```

@@ -166,21 +166,64 @@ The plugin uses WordPress' [background task manager](https://developer.wordpress By default, WordPress' task manager runs on every page load, which is inadvisable for production sites. For best performance and reliability, please ensure you have configured WordPress to use a [cron job](https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/) to run these tasks periodically instead. +## Features + +### Authentication with Universal Login + +The plugin hands authentication over to Auth0's Universal Login. Visitors sign in through your Auth0 tenant rather than the default WordPress login form, which lets you layer on Auth0 capabilities such as MFA, SSO, Passwordless, and Passkeys without changing your WordPress site. Authentication is turned on with a single "Enable Authentication" toggle once your Domain, Client ID, and Client Secret are configured. + +### WordPress user management + +You control how Auth0 logins map onto WordPress accounts. You can match an incoming Auth0 user to an existing WordPress account flexibly (by email) or strictly, decide whether a login without a matching WordPress account is denied or provisions a brand-new account, assign the default role granted to newly created accounts, and optionally allow Passwordless connections. + +### User synchronization + +The plugin can keep an Auth0 database connection in sync with your WordPress users. When enabled, creating, updating, or deleting a WordPress user is mirrored to the matching Auth0 user: new accounts are created (with a password-change ticket so the user can set their own password), profile changes are pushed (with an email-verification ticket when the email changes), and deletions are propagated. For performance and reliability the sync runs in the background through [WordPress' Cron](https://developer.wordpress.org/plugins/cron/) rather than blocking the request, and you can choose the sync frequency and which of the three event types (creation, update, deletion) are synchronized. + +### Advanced configuration + +A dedicated Advanced screen exposes the deeper Auth0 capabilities for sites that need them: + +- **Custom Domain, API Audiences, and Organizations** support for the Authentication API and token handling. +- **Session handling** — pairing WordPress and Auth0 sessions, rolling sessions, refresh tokens, configurable session lifetime, and a choice of device storage method. +- **Session cookies** — control over the cookie secret, domain, path, SSL requirement, SameSite policy, and expiration. +- **Token handling** — JWKS caching for signature verification. +- **Back-Channel Logout** — accept Auth0-initiated logout so a session ended at Auth0 also ends in WordPress. (Requires a tenant with this feature enabled.) +- **WordPress login fallback** — an optional escape hatch (with its own secret) to reach the standard WordPress login while Auth0 authentication is enabled. + ## SDK Usage The plugin is built on top of [Auth0-PHP](https://github.com/auth0/auth0-PHP) — Auth0's full-featured PHP SDK for Authentication and Management APIs. For custom WordPress development, please do not extend the plugin's classes themselves, as this is not supported. Nearly all of the plugin's APIs are considered `internal` and will change over time, most likely breaking any custom extension built upon them. -Instead, please take advantage of the full PHP SDK that the plugin is built upon. You can use the plugin's `getSdk()` method to retrieve a configured instance of the SDK, ready for use. This method can be called from the plugin's global `wpAuth0()` helper, which returns the WordPress plugin itself. +Instead, please take advantage of the full PHP SDK that the plugin is built upon. The plugin exposes two accessors from its global `wpAuth0()` helper (which returns the WordPress plugin itself): + +- `getSdk()` returns a configured `Auth0\SDK\Auth0` instance for the Authentication API and session handling. +- `getManagement()` returns a configured Management API client, built from the Domain, Client ID, and Client Secret in your plugin settings. It fetches and caches a client credentials token for you automatically. ```php getSdk(); // Returns an instanceof Auth0\SDK\Auth0 +use Auth0\SDK\API\Management\Users\Requests\ListUsersRequestParameters; + +$plugin = wpAuth0(); // Returns an instanceof Auth0\WordPress\Plugin +$sdk = wpAuth0()->getSdk(); // Returns an instanceof Auth0\SDK\Auth0 + +// Management API (v9): sub-resources are reached by property access. +$management = wpAuth0()->getManagement(); +$users = $management->users->list( + new ListUsersRequestParameters(['perPage' => 25, 'includeTotals' => true]) +); + +foreach ($users as $user) { + echo $user->getEmail(); +} ``` +> [!NOTE] +> As of 6.0, the Management API uses [auth0-php v9](https://github.com/auth0/auth0-php/tree/v9). The old `getSdk()->management()` entry point is no longer functional. If you are upgrading custom code from 5.x, see [UPGRADING.md](./UPGRADING.md) for the full set of changes. + Please direct questions about developing with the Auth0-PHP SDK to the [Auth0 Community](https://community.auth0.com), and issues or feature requests to [it's respective repository](https://github.com/auth0/auth0-PHP). Documentations and examples on working with the Auth0-PHP SDKs are also available from [its repository](https://github.com/auth0/auth0-PHP). ## Support Policy @@ -190,9 +233,10 @@ Please direct questions about developing with the Auth0-PHP SDK to the [Auth0 Co | Plugin Version | WordPress Version | PHP Version | Support Ends | | -------------- | ----------------- | ----------- | ------------ | -| 5 | 6 | 8.3 | Nov 2026 | -| | | 8.2 | Dec 2025 | -| | | 8.1 | Nov 2024 | +| 6 | 6 | 8.4 | Dec 2028 | +| | | 8.3 | Dec 2027 | +| | | 8.2 | Dec 2026 | +| 5 | 6 | 8.1 | Dec 2025 | Composer and WordPress do not offer upgrades to incompatible versions. Therefore, we regularly deprecate support within the plugin for PHP or WordPress versions that have reached end-of-life. These deprecations are not considered breaking changes and will not result in a major version bump. @@ -228,4 +272,4 @@ Please do not report security vulnerabilities on the public GitHub issue tracker

Auth0 is an easy-to-implement, adaptable authentication and authorization platform.
To learn more checkout Why Auth0?

-

This project is licensed under the MIT license. See the LICENSE file for more info.

\ No newline at end of file +

This project is licensed under the MIT license. See the LICENSE file for more info.

diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 000000000..44d7afa6e --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,48 @@ +# How to upgrade + +## 5.x to 6.x + +The 6.0 release moves the plugin onto [auth0-php v9](https://github.com/auth0/auth0-php/tree/v9), which rewrites the Management API. The authentication surface (login, logout, callback, session handling) is unchanged, so most sites only need the environment updates below. + +Check that your environment is compatible with 6.0's requirements before upgrading: + +| | 5.x | 6.x | +|---|---|---| +| **PHP** | `^8.1` | `^8.2` | +| **auth0/auth0-php** | `^8.19` | `^9.0` | + +- Please ensure you are running PHP 8.2 or newer. Support for PHP 8.1 has been dropped. +- The plugin bundles its dependencies, so updating the plugin pulls in `auth0/auth0-php` v9 automatically. No package rename is required; the package remains `auth0/auth0-php`. + +Update your customizations, if necessary: + +- **No changes are required for the plugin's built-in features.** Login, logout, the callback handler, user session handling, and the User Sync background jobs continue to work as they did in 5.x. The settings stored in the WordPress admin are unchanged. +- **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. + + ```php + // 5.x + $management = wpAuth0()->getSdk()->management(); + $response = $management->users()->getAll(['per_page' => 25]); + $users = HttpResponse::decodeContent($response); + + // 6.x + use Auth0\SDK\API\Management\Users\Requests\ListUsersRequestParameters; + + $management = wpAuth0()->getManagement(); + $users = $management->users->list( + new ListUsersRequestParameters(['perPage' => 25, 'includeTotals' => true]) + ); + foreach ($users as $user) { + echo $user->getEmail(); + } + ``` + + Inside a plugin action or filter class (anything extending `Auth0\WordPress\Actions\Base` or `Auth0\WordPress\Filters\Base`), the same client is available as `$this->getManagement()`. + +- If your custom code calls the Management API directly, review the [auth0-php v9 migration guide](https://github.com/auth0/auth0-php/blob/v9/v9_MIGRATION_GUIDE.md) for the full set of changes. The most common adjustments are: + - Sub-resources are reached by property access, not method calls: `->users->list()` rather than `->users()->getAll()`. + - Responses are typed objects instead of raw PSR-7 responses. Call `$response->jsonSerialize()` to get the same snake_case array the v8 `HttpResponse::decodeContent()` returned, or use the typed getters (`$response->getEmail()`). + - Errors throw exceptions. A non-2xx response raises `Auth0\SDK\API\Management\Exceptions\Auth0ApiException` (use `getCode()` for the HTTP status), and transport-level failures raise `Auth0\SDK\API\Management\Exceptions\Auth0Exception`. There is no more `HttpResponse::wasSuccessful()` check. + - Request parameters are camelCase typed objects. For example, creating a user takes a `CreateUserRequestContent` whose keys are `givenName` and `familyName` (not `given_name` / `family_name`), and the `connection` is set inside that object rather than passed as a separate argument. + - Listing users only returns the paginated envelope when `includeTotals` is set to `true`. Omitting it yields an empty result, so pass `'includeTotals' => true` when you page through users. + - Some ticket methods were renamed: `tickets()->createPasswordChange()` is now `tickets->changePassword()`, and `tickets()->createEmailVerification()` is now `tickets->verifyEmail()`. The user id moves inside the request object as `userId`. diff --git a/build.sh b/build.sh index c8a744536..2d0c0574f 100755 --- a/build.sh +++ b/build.sh @@ -34,18 +34,24 @@ echo "Version: $version" semver "$version" version filename="Auth0_WordPress_${version}.zip" +PLUGIN_NAME="wp-auth0" + echo "# Cleaning up environment..." rm -f build.zip rm -f build.zip.sig rm -rf build +rm -rf ${PLUGIN_NAME} rm -rf vendor -rm composer.lock +rm -f composer.lock echo "# Executing Composer..." composer update --no-plugins echo "# Prefixing Dependencies..." -vendor/bin/php-scoper add-prefix --force +php -d memory_limit=512M vendor/bin/php-scoper add-prefix --force + +echo "# Copying plugin entry file..." +cp wpAuth0.php build/wpAuth0.php echo "# Finalizing Build..." cd build @@ -54,8 +60,21 @@ rm composer.json rm composer.lock cd .. +echo "# Verifying scoped build (checking for incorrectly prefixed WordPress globals)..." +if grep -rn 'Auth0\\WordPress\\Vendor\\WP_' build/src/; then + echo "" + echo "ERROR: php-scoper has incorrectly prefixed WordPress global classes!" + echo "The above files contain 'Auth0\\WordPress\\Vendor\\WP_*' references that will cause fatal errors." + echo "Check scoper.inc.php expose-global-classes setting." + exit 1 +fi +echo " No incorrectly prefixed WordPress globals found. Build OK." + +echo "# Renaming build folder to ${PLUGIN_NAME}..." +mv build ${PLUGIN_NAME} + echo "# Archiving Build..." -zip -vr ${filename} build/ -x "*.DS_Store" +zip -vr ${filename} ${PLUGIN_NAME}/ -x "*.DS_Store" echo "# Signing Build..." openssl dgst -sign private-signing-key.pem -sha256 -out ${filename}.sig -binary ${filename} diff --git a/composer.json b/composer.json index f14c92fd3..db32d267e 100644 --- a/composer.json +++ b/composer.json @@ -33,10 +33,11 @@ "docs": "https://auth0.com/docs/customize/integrations/cms/wordpress-plugin" }, "require": { - "php": "^8.1", + "php": "^8.2", "ext-json": "*", "ext-openssl": "*", - "auth0/auth0-php": "^8.19", + "auth0/auth0-php": "^9.0@beta", + "nyholm/psr7": "^1", "psr/cache": "^3.0" }, "require-dev": { @@ -46,7 +47,6 @@ "friendsofphp/php-cs-fixer": "^3", "hyperf/event": "^2", "mockery/mockery": "^1", - "nyholm/psr7": "^1", "pestphp/pest": "^2", "phpstan/phpstan": "^1", "phpstan/phpstan-strict-rules": "^1", diff --git a/scoper.inc.php b/scoper.inc.php index e3b16c9d0..b64b57b37 100644 --- a/scoper.inc.php +++ b/scoper.inc.php @@ -8,10 +8,18 @@ 'prefix' => 'Auth0\\WordPress\\Vendor', 'finders' => [ + // Allowlist the plugin's own source; root files ship via append() below. + Finder::create() + ->files() + ->ignoreVCS(true) + ->in('src'), + + // jetbrains/phpstorm-stubs declares PHP internals (incl. assert()) as + // global functions; scoping them emits an illegal assert() wrapper that + // fatals scoper-autoload.php. Dev-only, stripped by --no-dev regardless. Finder::create() ->files() ->ignoreVCS(true) - ->notName('/.*\\.dist|Makefile|scoper.inc.php|rector.php|opslevel.yml|build.sh|public-signing-key.pub|composer.json|composer.lock/') ->exclude([ 'doc', 'test', @@ -19,11 +27,18 @@ 'tests', 'Tests', 'vendor-bin', + 'jetbrains', ]) - ->in(['vendor', '.']), + ->in('vendor'), + // Shippable root files (composer.json drives autoloading; build.sh strips it). Finder::create()->append([ 'composer.json', + 'CHANGELOG.md', + 'LICENSE.md', + 'README.md', + 'UPGRADING.md', + 'updates.json', ]), ], @@ -33,9 +48,46 @@ '/^Psr\\\/', ], - 'expose-global-constants' => false, - 'expose-global-classes' => false, - 'expose-global-functions' => false, + 'exclude-classes' => [ + '/^WP_/', + 'wpdb', + 'Walker', + 'WP_Widget', + ], + + 'exclude-functions' => [ + '/^wp_/', + '/^is_/', + '/^get_/', + '/^add_/', + '/^remove_/', + '/^do_/', + '/^apply_/', + '/^has_/', + '/^current_/', + '/^esc_/', + '/^__/', + '/^_e/', + '/^_x/', + '/^_n/', + '/^auth_redirect/', + '/^check_/', + '/^sanitize_/', + '/^absint/', + '/^home_url/', + '/^admin_url/', + '/^site_url/', + '/^plugin_/', + '/^register_/', + '/^settings_/', + '/^update_/', + '/^delete_/', + '/^set_/', + ], + + 'expose-global-constants' => true, + 'expose-global-classes' => true, + 'expose-global-functions' => true, 'patchers' => [], ]; diff --git a/src/Actions/Base.php b/src/Actions/Base.php index b2adc9d7b..b2aa7997e 100644 --- a/src/Actions/Base.php +++ b/src/Actions/Base.php @@ -4,6 +4,7 @@ namespace Auth0\WordPress\Actions; +use Auth0\SDK\API\Management\Wrapper\ManagementClient; use Auth0\SDK\Auth0; use Auth0\WordPress\{Hooks, Plugin}; @@ -69,6 +70,11 @@ final public function getPriority(string $event, int $default = 10, string $pref return $default; } + final public function getManagement(): ManagementClient + { + return $this->plugin->getManagement(); + } + final public function getSdk(): Auth0 { return $this->plugin->getSdk(); diff --git a/src/Actions/Configuration.php b/src/Actions/Configuration.php index 2e87baadc..3bc131532 100644 --- a/src/Actions/Configuration.php +++ b/src/Actions/Configuration.php @@ -4,8 +4,8 @@ namespace Auth0\WordPress\Actions; -use Auth0\SDK\Utility\HttpResponse; use Auth0\WordPress\Utilities\{Render, Sanitize}; +use Throwable; use function array_slice; use function count; @@ -934,12 +934,16 @@ public function onUpdateSync(?array $input): ?array } } - // Check if connection is valid - - $response = $this->getSdk()->management()->connections()->get($filteredDatabase); - - if (! HttpResponse::wasSuccessful($response)) { - $filteredDatabase = ''; + // Check if connection is valid. In v9 a non-2xx (e.g. an unknown + // connection id) raises Auth0ApiException rather than returning a + // response to inspect, so a thrown error means "not valid" and we + // clear the selection. + if ('' !== $filteredDatabase) { + try { + $this->getManagement()->connections->get($filteredDatabase); + } catch (Throwable) { + $filteredDatabase = ''; + } } // Setup background sync task: ----- diff --git a/src/Actions/Sync.php b/src/Actions/Sync.php index fd4fb1c33..f14e3df20 100644 --- a/src/Actions/Sync.php +++ b/src/Actions/Sync.php @@ -4,9 +4,12 @@ namespace Auth0\WordPress\Actions; -use Auth0\SDK\Utility\HttpResponse; +use Auth0\SDK\API\Management\Exceptions\Auth0ApiException; +use Auth0\SDK\API\Management\Tickets\Requests\{ChangePasswordTicketRequestContent, VerifyEmailTicketRequestContent}; +use Auth0\SDK\API\Management\Users\Requests\{CreateUserRequestContent, ListUsersByEmailRequestParameters, UpdateUserRequestContent}; use Auth0\WordPress\Database; -use Psr\Http\Message\ResponseInterface; +use JsonSerializable; +use Throwable; use WP_User; use function is_array; @@ -85,27 +88,30 @@ public function eventUserCreated(string $dbConnection, array $event): void $user = get_user_by('ID', $user); if ($user) { - $exists = $this->getResults($this->getSdk()->management()->usersByEmail()->get($user->user_email)); + $byEmail = $this->getManagement()->users->listUsersByEmail(new ListUsersByEmailRequestParameters([ + 'email' => $user->user_email, + ])); - if (! is_array($exists) || [] === $exists) { + if (! is_array($byEmail) || [] === $byEmail) { $dbConnectionName = $this->getDatabaseName($dbConnection); - $response = $this->getSdk()->management()->users()->create($dbConnectionName, [ + $created = $this->getManagement()->users->create(new CreateUserRequestContent([ + 'connection' => $dbConnectionName, + 'email' => $user->user_email, 'name' => $user->display_name, 'nickname' => $user->nickname, - 'given_name' => $user->user_firstname, - 'family_name' => $user->user_lastname, - 'email' => $user->user_email, + 'givenName' => $user->user_firstname, + 'familyName' => $user->user_lastname, 'password' => wp_generate_password(random_int(12, 123), true, true), - ]); + ])); - $response = $this->getResults($response, 201); + $response = $this->results($created); - if (null !== $response) { + if (null !== $response && isset($response['user_id'])) { // Trigger a password change email to let them set their password - $this->getSdk()->management()->tickets()->createPasswordChange([ - 'user_id' => $response['user_id'], - ]); + $this->getManagement()->tickets->changePassword(new ChangePasswordTicketRequestContent([ + 'userId' => $response['user_id'], + ])); $this->authentication()->createAccountConnection($user, $response['user_id']); } @@ -126,11 +132,11 @@ public function eventUserDeleted(string $dbConnection, array $event): void if (! $wpUser instanceof WP_User) { // Determine if the Auth0 counterpart account still exists - $api = $this->getResults($this->getSdk()->management()->users()->get($connection)); + $api = $this->results($this->getManagement()->users->get($connection)); if (null !== $api) { // Delete the Auth0 counterpart account - $this->getSdk()->management()->users()->delete($connection); + $this->getManagement()->users->delete($connection); } } } @@ -157,7 +163,7 @@ public function eventUserUpdated(string $dbConnection, array $event): void if (null !== $connections) { foreach ($connections as $connection) { - $api = $this->getResults($this->getSdk()->management()->users()->get($connection->auth0)); + $api = $this->results($this->getManagement()->users->get($connection->auth0)); if (null !== $api) { $connectionId = $api['user_id'] ?? null; @@ -168,16 +174,18 @@ public function eventUserUpdated(string $dbConnection, array $event): void $currentEmail = $api['email'] ?? ''; - $this->getSdk()->management()->users()->update($connectionId, [ + $this->getManagement()->users->update($connectionId, new UpdateUserRequestContent([ + 'email' => $user->user_email, 'name' => $user->display_name, 'nickname' => $user->nickname, - 'given_name' => $user->user_firstname, - 'family_name' => $user->user_lastname, - 'email' => $user->user_email, - ]); + 'givenName' => $user->user_firstname, + 'familyName' => $user->user_lastname, + ])); if ($user->user_email !== $currentEmail) { - $this->getSdk()->management()->tickets()->createEmailVerification($connectionId); + $this->getManagement()->tickets->verifyEmail(new VerifyEmailTicketRequestContent([ + 'userId' => $connectionId, + ])); } } } @@ -194,12 +202,12 @@ public function getDatabaseName(?string $dbConnection): ?string } if (null !== $dbConnection) { - $response = $this->getResults($this->getSdk()->management()->connections()->get($dbConnection)); + $response = $this->results($this->getManagement()->connections->get($dbConnection)); - if ($response) { + if (null !== $response && isset($response['name'])) { $dbConnectionName[$dbConnection] = $response['name']; - return $response['name'] ?? $dbConnection; + return $response['name']; } } @@ -232,19 +240,29 @@ public function onBackgroundSync(): void foreach ($queue as $singleQueue) { if (null !== $dbConnection) { - $payload = json_decode($singleQueue->payload, true, 512, JSON_THROW_ON_ERROR); + try { + $payload = json_decode($singleQueue->payload, true, 512, JSON_THROW_ON_ERROR); - if (isset($payload['event'])) { - if ('wp_user_created' === $payload['event'] && $enabledEvents['wp_user_created']) { - $this->eventUserCreated($dbConnection, $payload); - } + if (isset($payload['event'])) { + if ('wp_user_created' === $payload['event'] && $enabledEvents['wp_user_created']) { + $this->eventUserCreated($dbConnection, $payload); + } - if ('wp_user_deleted' === $payload['event'] && $enabledEvents['wp_user_deleted']) { - $this->eventUserDeleted($dbConnection, $payload); - } + if ('wp_user_deleted' === $payload['event'] && $enabledEvents['wp_user_deleted']) { + $this->eventUserDeleted($dbConnection, $payload); + } - if ('wp_user_updated' === $payload['event'] && $enabledEvents['wp_user_updated']) { - $this->eventUserUpdated($dbConnection, $payload); + if ('wp_user_updated' === $payload['event'] && $enabledEvents['wp_user_updated']) { + $this->eventUserUpdated($dbConnection, $payload); + } + } + } catch (Throwable $throwable) { + // A single failed item must not abort draining the rest of + // the queue; the row is still removed below to avoid a + // poison message blocking the queue indefinitely. + try { + error_log($throwable->getMessage()); + } catch (Throwable) { } } } @@ -272,12 +290,23 @@ private function authentication(): Authentication return $this->getPlugin()->getClassInstance(Authentication::class); } - private function getResults(ResponseInterface $response, int $expectedStatusCode = 200): ?array + /** + * Normalize a v9 Management response object into the snake_case array shape + * the rest of this class consumes. v9 endpoints return differently-typed + * response classes, but every one exposes a uniform jsonSerialize() that + * matches the v8 decoded-body shape, so serializing is the regeneration-safe + * way to read fields rather than relying on per-endpoint typed getters. + * + * @return ?array + */ + private function results(?JsonSerializable $response): ?array { - if (HttpResponse::wasSuccessful($response, $expectedStatusCode)) { - return HttpResponse::decodeContent($response); + if (! $response instanceof JsonSerializable) { + return null; } - return null; + $serialized = $response->jsonSerialize(); + + return is_array($serialized) ? $serialized : null; } } diff --git a/src/Plugin.php b/src/Plugin.php index 7e71e5c82..12c2fc699 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -4,6 +4,7 @@ namespace Auth0\WordPress; +use Auth0\SDK\API\Management\Wrapper\{ManagementClient, ManagementClientOptions}; use Auth0\SDK\Auth0; use Auth0\SDK\Configuration\SdkConfiguration; use Auth0\WordPress\Actions\{Authentication as AuthenticationActions, Base as Actions, Configuration as ConfigurationActions, Sync as SyncActions, Tools as ToolsActions, Updates as UpdatesActions}; @@ -35,6 +36,8 @@ final class Plugin */ private array $registry = []; + private ?ManagementClient $management = null; + public function __construct( private ?Auth0 $auth0, private ?SdkConfiguration $sdkConfiguration, @@ -168,6 +171,41 @@ public function getSdk(): Auth0 return $this->auth0; } + /** + * Returns a v9 Management API client built from the plugin's existing + * configuration. Use this instead of the v8-style `getSdk()->management()`, + * which is non-functional in auth0-php v9. + * + * The wrapper fetches and caches a client-credentials token internally. The + * plugin's own PSR-18 HTTP client is injected so the scoped build is used + * rather than runtime discovery, and the token is cached in the same + * WP_Object_Cache pool the SDK config uses (unless caching is disabled). + */ + public function getManagement(): ManagementClient + { + if (! $this->management instanceof ManagementClient) { + $configuration = $this->getConfiguration(); + + // The 'auth0' cache group is not registered as global, so in a + // multisite network WordPress prefixes its keys with the current + // blog id automatically. That keeps each site's Management token + // isolated without any per-site keying here. + $tokenCache = 'disable' !== $this->getOption('tokens', 'caching') + ? new WpObjectCachePool() + : null; + + $this->management = new ManagementClient(new ManagementClientOptions( + domain: (string) $configuration->getDomain(), + clientId: $configuration->getClientId(), + clientSecret: $configuration->getClientSecret(), + httpClient: Factory::getClient(), + tokenCache: $tokenCache, + )); + } + + return $this->management; + } + /** * Returns true if the plugin has been enabled. */ diff --git a/wpAuth0.php b/wpAuth0.php index 184b9e172..79024e30c 100644 --- a/wpAuth0.php +++ b/wpAuth0.php @@ -6,15 +6,14 @@ * Description: Supercharge your WordPress website with Auth0. Improve account security, add support for multifactor, enable social, passwordless and enterprise connections, and much more. * Version: 5.6.1 * Requires at least: 6.0 - * Tested up to: 6.5.3 + * Tested up to: 7.0 * Stable tag: 5.6.1 - * Requires PHP: 8.1 + * Requires PHP: 8.2 * Author: Auth0 * Author URI: https://auth0.com * License: MIT * License URI: https://github.com/auth0/wordpress/blob/master/LICENSE * Text Domain: wp-auth0 - * Domain Path: /languages */ declare(strict_types=1);