PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | src/myyoast-client/infrastructure/http/http-client.php +25 -3 27.8 → trunk View file →
@@ -133,16 +133,38 @@
133 133 );
134 134 }
135 135
136 136 /**
137 - * Checks if the response indicates a use_dpop_nonce error.
137 + * Checks if the response indicates a use_dpop_nonce challenge.
138 138 *
139 + * Covers both signalling shapes per RFC 9449 §§5.2 and 8:
140 + * - Authorization-server style: response body carries `{"error":"use_dpop_nonce"}`.
141 + * - Resource-server style: HTTP 401 with `WWW-Authenticate: DPoP error="use_dpop_nonce"` and a fresh `DPoP-Nonce` header.
142 + *
139 143 * @param HTTP_Response $result The parsed response.
140 144 *
141 - * @return bool Whether this is a DPoP nonce error.
145 + * @return bool Whether this is a DPoP nonce challenge.
142 146 */
143 147 private function is_dpop_nonce_error( HTTP_Response $result ): bool {
144 - return ( $result->get_body_value( 'error' ) === 'use_dpop_nonce' );
148 + if ( $result->get_body_value( 'error' ) === 'use_dpop_nonce' ) {
149 + return true;
150 + }
151 +
152 + if ( $result->get_status() !== 401 ) {
153 + return false;
154 + }
155 +
156 + $headers = $result->get_headers();
157 + if ( ! isset( $headers['www-authenticate'], $headers['dpop-nonce'] ) ) {
158 + return false;
159 + }
160 +
161 + $www_authenticate = $headers['www-authenticate'];
162 + if ( \is_array( $www_authenticate ) ) {
163 + $www_authenticate = (string) \reset( $www_authenticate );
164 + }
165 +
166 + return ( \stripos( (string) $www_authenticate, 'use_dpop_nonce' ) !== false );
145 167 }
146 168
147 169 /**
148 170 * Executes a single HTTP request with optional DPoP proof injection.