passbolt/passbolt_api · error · InternalErrorException
Invalid response. Invalid token endpoint.
Error message
Invalid response. Invalid token endpoint.
What it means
validateOpenIdConfiguration() checks token_endpoint with Validation::url(). If present but not a valid absolute URL, the token exchange endpoint is unusable and an InternalErrorException 'Invalid response. Invalid token endpoint.' is thrown. This is the final check in the discovery validation chain.
Solutions
- Inspect the discovery JSON; token_endpoint must be an absolute http(s) URL.
- Correct the IdP's base URL / endpoint configuration and republish metadata.
- Fix proxy/rewrite rules altering endpoint URLs.
- Retest SSO; the error disappears once the token endpoint validates.
Example fix
// before
'{"token_endpoint":"//auth.example.com/token"}'
// after
'{"token_endpoint":"https://auth.example.com/token"}' Defensive patterns
Strategy: validation
Validate before calling
use Cake\Validation\Validation;
$doc = json_decode(file_get_contents($wellKnownUrl), true);
if (!isset($doc['token_endpoint']) || !Validation::url($doc['token_endpoint'])) { throw new UnexpectedValueException('token_endpoint missing or not a valid absolute URL.'); } Type guard
function isValidTokenEndpoint(mixed $doc): bool { return is_array($doc) && isset($doc['token_endpoint']) && is_string($doc['token_endpoint']) && Validation::url($doc['token_endpoint']); } Try / catch
try { $tokenUrl = $provider->getBaseAccessTokenUrl(); } catch (InternalErrorException $e) { if (str_contains($e->getMessage(), 'Invalid token endpoint')) { /* metadata emits malformed token_endpoint */ } throw $e; } Prevention
- Set the IdP external base URL correctly so token_endpoint is absolute
- Re-check discovery metadata after network/proxy changes
- Validate all three endpoints (jwks_uri, authorization_endpoint, token_endpoint) during setup
- Log the discovery document on validation failure for quick diagnosis
When it happens
Trigger: Decoded discovery JSON contains token_endpoint whose value fails Validation::url() during the token-exchange setup via getBaseAccessTokenUrl.
Common situations: IdP publishing relative or malformed token endpoint URLs; proxy rewriting the metadata; self-hosted IdP with a misconfigured external base URL.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid response. Invalid authorization endpoint.
- Invalid response. Invalid JWKS URI
- Invalid response. Missing authorization endpoint.
- Invalid response. Missing JWKS URI
- Invalid response. Missing token endpoint.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/5a23ae14816a1fee.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/Provider/AbstractOauth2Provider.php:190
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);
/**
* The "approval_prompt" MUST be removed as it is not supported by Google, use "prompt" instead:
*
* @link https://developers.google.com/identity/protocols/oauth2/openid-connect#prompt
*/
unset($options['approval_prompt']);
return $options;View on GitHub (pinned to 31c1bbc10f)