passbolt/passbolt_api · error · InternalErrorException
Invalid JWKS endpoint response. Keys missing.
Error message
Invalid JWKS endpoint response. Keys missing.
What it means
After successfully fetching the JWKS endpoint, the provider expects an object/array containing a 'keys' member (per RFC 7517). If the response is not an array or lacks 'keys', the IdP returned something unexpected and the provider throws this InternalErrorException because JWT signature verification is impossible without the key set.
Solutions
- Fetch the JWKS URI manually and confirm the response contains a top-level 'keys' array (RFC 7517 format)
- Fix the SSO provider configuration/discovery URL if it points to a non-JWKS endpoint
- Check for interceptors (proxy, WAF) returning 200 with an error body instead of the actual key set
- Clear any caching layer serving a stale or corrupted JWKS response
- If the IdP changed its JWKS format/version, upgrade the SSO plugin
Defensive patterns
Strategy: validation
Validate before calling
$payload = json_decode(file_get_contents($provider->getJwksUri()), true);
if (!is_array($payload) || !isset($payload['keys'])) {
throw new \RuntimeException('IdP returned malformed JWKS; check discovery URL and proxies');
} Try / catch
try {
$keys = $provider->getJwtVerificationKeys();
} catch (\Cake\Http\Exception\InternalErrorException $e) {
if (str_contains($e->getMessage(), 'Keys missing')) {
// surface IdP misconfiguration guidance to the admin
}
} Prevention
- Confirm the JWKS URL returns RFC 7517 format with a top-level 'keys' array
- Check for proxies/WAFs that substitute 200-error pages for real responses
- Pin and validate discovery metadata when configuring the provider
- Re-verify after IdP API version upgrades
When it happens
Trigger: getJwtVerificationKeys() receives a parsed response that is not an array, or an array without a 'keys' index — e.g. the JWKS URI returned JSON like {"error":"..."}, an empty object, or a plain list.
Common situations: A reverse proxy or captive portal returns an HTML/JSON error page with 200 status; misconfigured discovery metadata pointing at the wrong endpoint; an IdP API version change altering the response shape.
Related errors
- Cannot parse JWKS endpoint response.
- AccessToken should be an instance of BaseIdToken class.
- Cannot parse JWKS endpoint response.
- $data['error'] (dynamic provider error)
- $data['error'] (dynamic provider error)
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/32cb51a8320d2b42.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php:285
*
* @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(): mixed
{
return Configure::read('passbolt.plugins.sso.security.jwks.defaultAlg');
}
View on GitHub (pinned to 31c1bbc10f)