{"record":{"id":"9b2a65e549266a7f","repo":"passbolt/passbolt_api","slug":"response-getreasonphrase-dynamic-provider-error","errorCode":null,"errorMessage":"$response->getReasonPhrase() (dynamic provider error)","messagePattern":"\\$response->getReasonPhrase\\(\\) \\(dynamic provider error\\)","errorType":"exception","errorClass":"IdentityProviderException","httpStatus":null,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Utility/Google/Provider/GoogleProvider.php","lineNumber":71,"sourceCode":"     */\n    protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface\n    {\n        return new GoogleResourceOwner($response);\n    }\n\n    /**\n     * @inheritDoc\n     */\n    protected function checkResponse(ResponseInterface $response, $data): void\n    {\n        if (empty($data['error'])) {\n            return;\n        }\n\n        if (is_string($data['error']) && isset($data['error_description']) && is_string($data['error_description'])) {\n            throw new GoogleException($data['error'], $data['error_description']);\n        } else {\n            throw new IdentityProviderException(\n                $response->getReasonPhrase(),\n                $response->getStatusCode(),\n                (string)$response->getBody()\n            );\n        }\n    }\n}\n","sourceCodeStart":53,"sourceCodeEnd":79,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Utility/Google/Provider/GoogleProvider.php#L53-L79","documentation":"When Google's response contains an 'error' key but not in the expected string error/error_description shape, checkResponse() falls back to throwing league/oauth2-client's IdentityProviderException built from the raw HTTP status line, status code and body. This covers malformed or non-standard error payloads (arrays, HTML error pages, empty bodies with error status codes).","triggerScenarios":"Google (or an intermediary proxy) returns a non-JSON or malformed error body — e.g. an HTML 502/503 page from a load balancer, a JSON error object where 'error' is an array — while data['error'] is non-empty, so the structured GoogleException branch does not apply.","commonSituations":"Corporate proxies/firewalls intercepting outbound calls to accounts.google.com; Google outages returning HTML error pages; MTU or TLS issues producing truncated responses; mismatched response parsing when response body isn't JSON.","solutions":["Inspect the exception's response body/data to see the raw payload and HTTP status code to identify what actually came back.","Verify the server can reach accounts.google.com directly (curl) and that no proxy intercepts HTTPS traffic with its own error pages.","Update the league/oauth2-client / guzzle packages to current versions to ensure consistent response parsing.","If behind a proxy, add accounts.google.com to the egress allowlist and disable HTTPS interception for it.","Retry after confirming Google status dashboards show no incident."],"exampleFix":"// before: proxy returns HTML for blocked hosts\n// data['error'] is set but non-string (parsed garbage) -> IdentityProviderException with raw body\n// after: allow Google through the egress proxy so real JSON reaches checkResponse()\ncurl -I https://accounts.google.com/.well-known/openid-configuration\n# expect HTTP 200 and application/json, not a proxy HTML error page","handlingStrategy":"try-catch","validationCode":"$decoded = json_decode((string)$response->getBody(), true);\nif (json_last_error() !== JSON_ERROR_NONE || !is_array($decoded)) {\n    // non-JSON body from Google or an intercepting proxy — fail fast with a clear message\n}","typeGuard":null,"tryCatchPattern":"try {\n    $token = $provider->getAccessToken('jwt_bearer', [...]);\n} catch (\\League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException $e) {\n    $this->log('HTTP ' . $e->getCode() . ' from Google: ' . $e->getResponseBody());\n    // treat as infrastructure/proxy problem, not user error\n}","preventionTips":["Ensure direct egress to accounts.google.com without HTTPS-intercepting proxies","Pin and update league/oauth2-client and guzzlehttp/guzzle versions","Check response Content-Type is application/json in integration tests","Alert on 5xx HTML bodies from the IdP path"],"tags":["sso","google","oauth2","http-error","identity-provider"],"backgroundTag":"http-error-response","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}