passbolt/passbolt_api · error · InternalErrorException
Invalid response. Missing token endpoint.
Error message
Invalid response. Missing token endpoint.
What it means
validateOpenIdConfiguration() requires token_endpoint in the discovery document because passbolt exchanges the authorization code for tokens there (getBaseAccessTokenUrl). Its absence indicates an incomplete OIDC discovery payload, so an InternalErrorException is thrown.
Solutions
- Curl the discovery URL and verify token_endpoint is present.
- Fix the issuer/WellKnownURI configured in passbolt SSO settings.
- Purge intermediary caches/proxies serving stale discovery metadata.
- Reconfigure the IdP to publish compliant discovery metadata.
Example fix
// before
'{"jwks_uri":"https://auth.example.com/jwks"}'
// after
'{"token_endpoint":"https://auth.example.com/token","jwks_uri":"https://auth.example.com/jwks"}' Defensive patterns
Strategy: validation
Validate before calling
$doc = json_decode(file_get_contents($wellKnownUrl), true);
if (!isset($doc['token_endpoint'])) { throw new UnexpectedValueException('Discovery document missing token_endpoint.'); } Type guard
function hasTokenEndpoint(mixed $doc): bool { return is_array($doc) && isset($doc['token_endpoint']) && is_string($doc['token_endpoint']); } Try / catch
try { $tokenUrl = $provider->getBaseAccessTokenUrl(); } catch (InternalErrorException $e) { if (str_contains($e->getMessage(), 'token endpoint')) { /* incomplete discovery metadata */ } throw $e; } Prevention
- Check the discovery document lists token_endpoint before enabling code flow
- Clear stale caches/proxies that may serve partial metadata
- Re-verify metadata after IdP reconfiguration
- Use a setup wizard that validates all required OIDC fields
When it happens
Trigger: getBaseAccessTokenUrl -> getOpenIdConfiguration -> validateOpenIdConfiguration with decoded JSON missing the token_endpoint key.
Common situations: IdP publishing partial metadata; discovery URL resolving to a different app's document; proxy/cache serving stale metadata; misconfigured multi-tenant issuer.
Related errors
- Invalid response. Invalid authorization endpoint.
- Invalid response. Invalid token endpoint.
- Invalid response. Missing authorization endpoint.
- Invalid response. Missing JWKS URI
- Invalid response. Expected array, got
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/7b2121973f071f98.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php:181
{
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.');
}
}
/**
* @inheritDoc
*/
protected function getAuthorizationParameters(array $options)
{
$options = parent::getAuthorizationParameters($options);View on GitHub (pinned to 31c1bbc10f)