passbolt/passbolt_api · error · InternalErrorException

Cannot parse JWKS endpoint response.

Error message

Cannot parse JWKS endpoint response.

What it means

AzureProvider::getJwtVerificationKeys() fetches the JWKS (public keys) document from Azure's discovery config via getParsedResponse(); any Throwable (network error, HTTP error, JSON parse failure) is wrapped in InternalErrorException with this message, since verification keys are mandatory for validating ID tokens.

Solutions

  1. Test connectivity from the server: curl the JWKS URI found in the OpenID config
  2. Configure outbound proxy/firewall rules to allow HTTPS to login.microsoftonline.com
  3. Clear cached OpenID metadata and retry the SSO setup to refresh the keys URI
  4. Check the wrapped exception in the log for the underlying network/parse cause

Example fix

// server-side connectivity check
// before: request fails silently behind firewall
// after: allow egress
curl -i https://login.microsoftonline.com/common/discovery/v2.0/keys
Defensive patterns

Strategy: retry

Validate before calling

$response = Http::get($keysUri); if (!$response->isOk() || !is_array($response->getJson()['keys'] ?? null)) { /* JWKS unreachable, retry/degrade */ }

Type guard

function isValidJwks(mixed $response): bool { return is_array($response) && isset($response['keys']) && is_array($response['keys']); }

Try / catch

try { $keys = $provider->getJwtVerificationKeys(); } catch (InternalErrorException $e) { Log::error('JWKS fetch failed: ' . $e->getPrevious()?->getMessage()); return $this->respondError(503, 'Unable to reach identity provider keys.'); }

Prevention

When it happens

Trigger: HTTP request to the JWKS URI fails or the response cannot be parsed — DNS failure, TLS error, timeout, 4xx/5xx from Azure, or non-JSON body.

Common situations: Server has no outbound internet access or blocked by firewall; proxy required but not configured; Azure jwks URI temporarily unreachable; discovery document cached with an outdated keys URI; clock/TLS issues on the server.

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


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

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/Azure/Provider/AzureProvider.php:169

    }

    /**
     * Get JWT verification keys from Azure Active Directory.
     *
     * @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.'));
        }

        /**
         * Here we are using custom method to check JWK key signature as we can't use `JWK::parseKeySet` method directly
         * because Azure don't provide "kty" parameter in the keys.
         *
         * @see \Firebase\JWT\JWK::parseKeySet()
         */
        return $this->parseJwksKeys($response['keys']);
    }

    /**
     * Parse & check JWT keys signature from Azure.
     *

View on GitHub (pinned to 31c1bbc10f)