passbolt/passbolt_api · error · InternalErrorException
Cannot parse JWKS endpoint response.
Error message
Cannot parse JWKS endpoint response.
What it means
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.
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
Example fix
// verify JWKS endpoint from the server
// before (failing implicitly)
$keys = $provider->getJwtVerificationKeys();
// after: guard with connectivity check
$keysUri = $provider->getJwksUri();
if (@file_get_contents($keysUri) === false) {
throw new RuntimeException('JWKS endpoint unreachable: ' . $keysUri);
}
$keys = $provider->getJwtVerificationKeys(); Defensive patterns
Strategy: retry
Validate before calling
$ch = curl_init($provider->getJwksUri());
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status !== 200 || json_decode($body) === null) {
throw new \RuntimeException('JWKS endpoint not reachable or not JSON');
} Try / catch
try {
$keys = $provider->getJwtVerificationKeys();
} catch (\Cake\Http\Exception\InternalErrorException $e) {
$root = $e->getPrevious();
$this->log('JWKS fetch failed: ' . ($root ? $root->getMessage() : $e->getMessage()));
// optionally retry once, then fail the SSO login with a user-facing error
} Prevention
- 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
When it happens
Trigger: 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().
Common situations: 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.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Cannot parse JWKS endpoint response.
- $exception->getMessage() (dynamic wrapped error)
- Invalid JWKS endpoint response. Keys missing.
- AccessToken should be an instance of BaseIdToken class.
- Ajax/Json request not supported.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/d19637a427b5d856.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php:281
}
/**
* Get JWT verification keys from Google.
*
* @return array
*/
public function getJwtVerificationKeys(): array
{
$openIdConfiguration = $this->getOpenIdConfiguration();
$keysUri = $openIdConfiguration['jwks_uri'];
$factory = $this->getRequestFactory();
$request = $factory->getRequestWithOptions('get', $keysUri, []);
try {
$response = $this->getParsedResponse($request);
} catch (Throwable $exception) {
throw new InternalErrorException(__('Cannot parse JWKS endpoint response.'), 500, $exception);
}
if (!is_array($response) || !isset($response['keys'])) {
throw new InternalErrorException(__('Invalid JWKS endpoint response. Keys missing.'));
}
$defaultAlg = $this->getJwksDefaultAlg();
$this->assertJwkDefaultAlg($defaultAlg);
return JWK::parseKeySet($response, $defaultAlg);
}
/**
* Returns the alg of the keys.
*
* @return mixed
*/
protected function getJwksDefaultAlg(): mixedView on GitHub (pinned to 31c1bbc10f)