{"record":{"id":"d19637a427b5d856","repo":"passbolt/passbolt_api","slug":"cannot-parse-jwks-endpoint-response-abstractoauth2provider","errorCode":null,"errorMessage":"Cannot parse JWKS endpoint response.","messagePattern":"Cannot parse JWKS endpoint response\\.","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php","lineNumber":281,"sourceCode":"    }\n\n    /**\n     * Get JWT verification keys from Google.\n     *\n     * @return array\n     */\n    public function getJwtVerificationKeys(): array\n    {\n        $openIdConfiguration = $this->getOpenIdConfiguration();\n        $keysUri = $openIdConfiguration['jwks_uri'];\n\n        $factory = $this->getRequestFactory();\n        $request = $factory->getRequestWithOptions('get', $keysUri, []);\n\n        try {\n            $response = $this->getParsedResponse($request);\n        } catch (Throwable $exception) {\n            throw new InternalErrorException(__('Cannot parse JWKS endpoint response.'), 500, $exception);\n        }\n\n        if (!is_array($response) || !isset($response['keys'])) {\n            throw new InternalErrorException(__('Invalid JWKS endpoint response. Keys missing.'));\n        }\n\n        $defaultAlg = $this->getJwksDefaultAlg();\n        $this->assertJwkDefaultAlg($defaultAlg);\n\n        return JWK::parseKeySet($response, $defaultAlg);\n    }\n\n    /**\n     * Returns the alg of the keys.\n     *\n     * @return mixed\n     */\n    protected function getJwksDefaultAlg(): mixed","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php#L263-L299","documentation":"getJwtVerificationKeys() fetches the identity provider's JWKS endpoint and parses the response. If the HTTP request/response processing throws for any reason (network failure, non-200 status, malformed JSON), the error is wrapped in this InternalErrorException to signal that the JWKS could not be obtained/parsed.","triggerScenarios":"The IdP's JWKS URI is unreachable, returns a non-2xx response, times out, or returns a body that cannot be parsed — i.e. getParsedResponse() throws any Throwable during getJwtVerificationKeys().","commonSituations":"SSO login/recover with Google/Azure/ADFS when the IdP is temporarily down, DNS or proxy issues, firewall blocking outbound HTTPS, wrong discovery/jwks URI configured, or an unexpected HTML error page instead of JSON.","solutions":["Check server-to-server connectivity: curl the provider's JWKS URI from the passbolt server and confirm a 200 JSON response with a 'keys' array","Retry after confirming the IdP status page / outage; transient IdP errors are a common cause","Verify SSO provider settings (domain, discovery URL) so the resolved JWKS URI is correct","Inspect the chained exception in the error log (third argument) for the root cause (DNS, TLS, timeout)","Check proxy/firewall configuration on the passbolt host for outbound requests"],"exampleFix":"// verify JWKS endpoint from the server\n// before (failing implicitly)\n$keys = $provider->getJwtVerificationKeys();\n// after: guard with connectivity check\n$keysUri = $provider->getJwksUri();\nif (@file_get_contents($keysUri) === false) {\n    throw new RuntimeException('JWKS endpoint unreachable: ' . $keysUri);\n}\n$keys = $provider->getJwtVerificationKeys();","handlingStrategy":"retry","validationCode":"$ch = curl_init($provider->getJwksUri());\ncurl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);\n$body = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);\nif ($status !== 200 || json_decode($body) === null) {\n    throw new \\RuntimeException('JWKS endpoint not reachable or not JSON');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $keys = $provider->getJwtVerificationKeys();\n} catch (\\Cake\\Http\\Exception\\InternalErrorException $e) {\n    $root = $e->getPrevious();\n    $this->log('JWKS fetch failed: ' . ($root ? $root->getMessage() : $e->getMessage()));\n    // optionally retry once, then fail the SSO login with a user-facing error\n}","preventionTips":["Monitor outbound HTTPS connectivity from the passbolt server to IdP JWKS endpoints","Verify discovery/JWKS URLs whenever SSO settings change","Allowlist IdP domains in firewall/proxy config","Log chained exceptions to distinguish network vs parsing failures"],"tags":["network","jwks","oauth2","sso","http"],"backgroundTag":"http-request-failed","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"}