Skip to content

Commit 9724ffd

Browse files
Apply callback URL change detection to legacy AI_Authorization namespace
Same fix as src/ai/authorization/ — both copies are active in the compiled DI container and register identical REST routes.
1 parent d2ec6ee commit 9724ffd

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

src/ai-authorization/application/token-manager.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,23 @@ public function token_request( WP_User $user ): void {
202202
$code_verifier = $this->code_verifier->generate( $user->user_email );
203203
$this->code_verifier_repository->store_code_verifier( $user->ID, $code_verifier->get_code(), $code_verifier->get_created_at() );
204204

205+
$callback_url = $this->urls->get_callback_url();
206+
$refresh_callback_url = $this->urls->get_refresh_callback_url();
207+
205208
$request_body = [
206209
'service' => 'openai',
207210
'code_challenge' => \hash( 'sha256', $code_verifier->get_code() ),
208211
'license_site_url' => WPSEO_Utils::get_home_url(),
209212
'user_id' => (string) $user->ID,
210-
'callback_url' => $this->urls->get_callback_url(),
211-
'refresh_callback_url' => $this->urls->get_refresh_callback_url(),
213+
'callback_url' => $callback_url,
214+
'refresh_callback_url' => $refresh_callback_url,
212215
];
213216

214217
$this->request_handler->handle( new Request( '/token/request', $request_body ) );
215218

219+
// Store a per-user hash of the callback URL to detect future site URL changes.
220+
$this->user_helper->update_meta( $user->ID, '_yoast_wpseo_ai_generator_callback_url_hash', \md5( $callback_url ) );
221+
216222
// The callback saves the metadata. Because that is in another session, we need to delete the current cache here. Or we may get the old token.
217223
\wp_cache_delete( $user->ID, 'user_meta' );
218224
}
@@ -306,6 +312,12 @@ public function has_token_expired( string $jwt ): bool {
306312
* @throws RuntimeException Unable to retrieve the access or refresh token.
307313
*/
308314
public function get_or_request_access_token( WP_User $user ): string {
315+
// If the site URL has changed since callback URLs were registered, delete stale tokens.
316+
if ( $this->have_callback_urls_changed( $user ) ) {
317+
$this->user_helper->delete_meta( $user->ID, '_yoast_wpseo_ai_generator_access_jwt' );
318+
$this->user_helper->delete_meta( $user->ID, '_yoast_wpseo_ai_generator_refresh_jwt' );
319+
}
320+
309321
$access_jwt = $this->user_helper->get_meta( $user->ID, '_yoast_wpseo_ai_generator_access_jwt', true );
310322
if ( ! \is_string( $access_jwt ) || $access_jwt === '' ) {
311323
$this->token_request( $user );
@@ -330,4 +342,30 @@ public function get_or_request_access_token( WP_User $user ): string {
330342
}
331343

332344
// phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
345+
346+
/**
347+
* Checks whether the callback URLs have changed since the last token request.
348+
*
349+
* Detects site URL changes (e.g., migrating from a staging URL to a production domain)
350+
* that would leave stale callback URLs registered with the Yoast AI service.
351+
* Uses a per-user hash so each user independently detects the change and re-registers.
352+
* The hash is immune to wp search-replace operations.
353+
*
354+
* When no hash is stored (first run after upgrade), returns true to force a fresh
355+
* token_request(). This ensures existing sites with stale callback URLs self-heal
356+
* without manual intervention.
357+
*
358+
* @param WP_User $user The current user.
359+
*
360+
* @return bool Whether the callback URLs may have changed.
361+
*/
362+
private function have_callback_urls_changed( WP_User $user ): bool {
363+
$registered_hash = $this->user_helper->get_meta( $user->ID, '_yoast_wpseo_ai_generator_callback_url_hash', true );
364+
365+
if ( ! \is_string( $registered_hash ) || $registered_hash === '' ) {
366+
return true;
367+
}
368+
369+
return $registered_hash !== \md5( $this->urls->get_callback_url() );
370+
}
333371
}

0 commit comments

Comments
 (0)