passbolt/passbolt_api · error · InternalErrorException

Invalid response. Missing JWKS URI

Error message

Invalid response. Missing JWKS URI

What it means

After confirming the discovery document is an array, validateOpenIdConfiguration() checks required OIDC metadata fields. A decoded JSON without a jwks_uri key means the provider did not advertise its JSON Web Key Set endpoint, which passbolt needs to verify ID token signatures, so it throws this InternalErrorException.

Solutions

  1. Curl the discovery URL and confirm jwks_uri is present in the JSON.
  2. Ensure the selected SSO provider is actually an OpenID Connect provider (OAuth2-only providers lack jwks_uri).
  3. Point passbolt at a compliant OIDC issuer for the same IdP.
  4. If the IdP genuinely omits jwks_uri, switch to a flow/algorithm setup not requiring JWKS or contact the IdP vendor.

Example fix

// before (OAuth2-only endpoint without JWKS)
'issuer' => 'https://oauth.example.com',
// after (OIDC-compliant issuer)
'issuer' => 'https://auth.example.com/oidc',
Defensive patterns

Strategy: validation

Validate before calling

$doc = json_decode(file_get_contents($wellKnownUrl), true);
if (!isset($doc['jwks_uri'])) { throw new UnexpectedValueException('Provider is not OIDC-compliant: jwks_uri missing from discovery document.'); }

Type guard

function hasJwksUri(mixed $doc): bool { return is_array($doc) && isset($doc['jwks_uri']) && is_string($doc['jwks_uri']); }

Try / catch

try { $keys = $provider->getJwtVerificationKeys(); } catch (InternalErrorException $e) { if ($e->getMessage() === 'Invalid response. Missing JWKS URI') { /* IdP is OAuth2-only or metadata incomplete */ } throw $e; }

Prevention

When it happens

Trigger: The IdP's .well-known/openid-configuration JSON decodes to an array but lacks the jwks_uri field; discovered during getJwtVerificationKeys via getOpenIdConfiguration.

Common situations: Provider is OAuth2-only (not OIDC) so it publishes no JWKS; partial/non-compliant discovery document; a proxy returning a trimmed/custom JSON body; wrong provider type selected in passbolt SSO settings.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/9f3ce563100d3200. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php:175

     * Check the endpoints info we expect to use later are present
     *
     * @param mixed $response from .well-known
     * @return void
     */
    public function validateOpenIdConfiguration(mixed $response): void
    {
        if (!is_array($response)) {
            $msg = sprintf('Invalid response. Expected array, got "%s".', gettype($response));
            if (is_string($response)) {
                // Cap excerpt to limit log volume on large/HTML responses; mb_strcut is UTF-8-safe.
                $excerpt = mb_strcut($response, 0, 200, 'UTF-8');
                // Escape newlines and control characters via JSON encoding so they don't corrupt log output.
                $msg .= ' ' . sprintf('Response text (truncated): %s', json_encode($excerpt));
            }
            throw new InternalErrorException($msg);
        }
        if (!isset($response['jwks_uri'])) {
            throw new InternalErrorException('Invalid response. Missing JWKS URI');
        }
        if (!isset($response['authorization_endpoint'])) {
            throw new InternalErrorException('Invalid response. Missing authorization endpoint.');
        }
        if (!isset($response['token_endpoint'])) {
            throw new InternalErrorException('Invalid response. Missing token endpoint.');
        }
        if (!Validation::url($response['jwks_uri'])) {
            throw new InternalErrorException('Invalid response. Invalid JWKS URI');
        }
        if (!Validation::url($response['authorization_endpoint'])) {
            throw new InternalErrorException('Invalid response. Invalid authorization endpoint.');
        }
        if (!Validation::url($response['token_endpoint'])) {
            throw new InternalErrorException('Invalid response. Invalid token endpoint.');
        }
    }

View on GitHub (pinned to 31c1bbc10f)