Revoke consent by invalidating tokens#23425
Conversation
Coverage Report for CI Build 0Warning No base build found for commit Coverage: 49.455%Details
Uncovered Changes
Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
|
A merge conflict has been detected for the proposed code changes in this PR. Please resolve the conflict by either rebasing the PR or merging in changes from the base branch. |
Resolve conflicts in the new-structure Consent_Handler and its Revoke_Consent_Test by taking trunk's auth-strategy refactor; our route, token-manager, and legacy revoke changes merge cleanly on top. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the Yoast AI consent revocation flow to avoid re-provisioning tokens when revoking consent, aligning JWT-based revocation with the /token/invalidate endpoint while keeping OAuth-based revocation on DELETE /user/consent. It also fixes a regression where sending an empty array body on POST could break requests by omitting empty bodies entirely.
Changes:
- Reworks consent revocation so JWT-based sites revoke consent via token invalidation (and always clear local JWTs), while OAuth-based sites revoke via
DELETE /user/consent. - Ensures empty POST bodies are omitted (Request body becomes
nullwhen empty, and API client skips encoding/sending it). - Adds/updates unit tests for revoke-consent behavior and for token invalidation clearing local tokens even when the remote call fails.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/AI/Consent/User_Interface/Consent_Route/Consent_Test.php | Updates route tests to reflect revocation being handled by the consent handler (no direct token invalidation call expected). |
| tests/Unit/AI/Consent/Application/Consent_Handler/Revoke_Consent_Test.php | Adjusts expectations to the new revoke behavior (no longer asserting a returned Response from revoke call). |
| tests/Unit/AI/Authorization/Application/Token_Manager/Token_Invalidate_Test.php | Aligns token invalidation request expectations (no body) and adds coverage for local token clearing on remote failure. |
| tests/Unit/AI/Authentication/Application/Token_Auth_Strategy/Token_Auth_Strategy_Test.php | Adds a test ensuring revoke consent invalidates tokens and does not provision new ones. |
| tests/Unit/AI/Authentication/Application/OAuth_Auth_Strategy/Revoke_Consent_Test.php | New test verifying OAuth revoke consent dispatches authenticated DELETE with user_id in query and no body. |
| tests/Unit/AI/Authentication/Application/AI_Request_Sender/AI_Request_Sender_Test.php | Adds a test ensuring revoke consent delegates to primary strategy only; updates expectations for empty bodies becoming null. |
| src/ai/http-request/infrastructure/api-client.php | Omits POST body entirely when empty to avoid AI service rejecting []. |
| src/ai/http-request/infrastructure/api-client-interface.php | Updates PHPDoc to allow null/empty body semantics. |
| src/ai/http-request/domain/request.php | Changes get_body() to return null for empty arrays to represent “no body”. |
| src/ai/consent/user-interface/consent-route.php | Switches revoke path to Consent_Handler::revoke_consent() (no longer calling Token_Manager directly). |
| src/ai/authorization/application/token-manager.php | Sends token invalidation with no body and always clears local tokens in a finally block. |
| src/ai/authentication/application/token-auth-strategy.php | Implements revoke_consent() by invalidating tokens (no new token provisioning). |
| src/ai/authentication/application/oauth-auth-strategy.php | Safely merges nullable request bodies for POST; adds revoke_consent() via authenticated DELETE. |
| src/ai/authentication/application/auth-strategy-interface.php | Adds revoke_consent() to the auth strategy contract. |
| src/ai/authentication/application/ai-request-sender.php | Changes revoke consent to delegate only to the primary strategy and return void. |
| src/ai-http-request/infrastructure/api-client.php | Mirrors empty-body omission behavior in the ai- mirrored structure. |
| src/ai-http-request/infrastructure/api-client-interface.php | Mirrors PHPDoc updates in the ai- mirrored structure. |
| src/ai-http-request/domain/request.php | Mirrors get_body(): ?array empty-body behavior in the ai- mirrored structure. |
| src/ai-consent/user-interface/consent-route.php | Mirrors route revoke delegation change in the ai- mirrored structure. |
| src/ai-consent/application/consent-handler.php | Updates revoke to use token invalidation instead of DELETE /user/consent (legacy/JWT path). |
| src/ai-authorization/application/token-manager.php | Mirrors token invalidation changes (no body + always clear local tokens) in the ai- mirrored structure. |
Context
ai-structure, but we dont have to test thenew Free + 27.1 Premiumas per this, so the code changes in those files dont come with test instructions. We do ship those changes for completeness sake.Summary
This PR can be summarized in the following changelog entry:
Relevant technical choices:
Test instructions
Test instructions for the acceptance test before the PR gets merged
This PR can be acceptance tested by following these steps:
Do the below steps with
Testing in JWT-based flow
define( 'YOAST_SEO_MYYOAST_CONNECTION', true );activeGrant consentand confirm that everything went great.Revoke consentand confirm that everything went great.Grant consent_yoast_wpseo_ai_generator_access_jwtand_yoast_wpseo_ai_generator_refresh_jwtdoesn't exists in your usermeta_yoast_wpseo_ai_generator_access_jwtand_yoast_wpseo_ai_generator_refresh_jwtexists in your usermetaRevoke consent.500status and aFailed to revoke consentmessageWARNING - Primary AI auth strategy failed (UNKNOWN, HTTP 500: Simulated AI service failure); the failure is not recoverable by the fallback, propagating to the caller.which is the failure of the revoke consentERROR - Simulated AI service failurewhich is the failure of the token invalidationwp_usermeta, verify_yoast_wpseo_ai_consentfor your user is deleted despite the simulated failure.wp_usermeta, verify_yoast_wpseo_ai_generator_access_jwtfor your user is deleted despite the simulated failure. Same for_yoast_wpseo_ai_generator_refresh_jwtTesting in OAuth-based flow
_yoast_wpseo_ai_generator_access_jwttokens locally, to make sure they can cleaned up after.define( 'YOAST_SEO_MYYOAST_CONNECTION', true );activeRelevant test scenarios
Test instructions for QA when the code is in the RC
QA can test this PR by following these steps:
Impact check
This PR affects the following parts of the plugin, which may require extra testing:
Other environments
[shopify-seo], added test instructions for Shopify and attached theShopifylabel to this PR.[yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached theGoogle Docs Add-onlabel to this PR.Documentation
Quality assurance
grunt build:imagesand committed the results, if my PR introduces or edits images or SVGs.Innovation
innovationlabel.Fixes #