BookStackApp/BookStack · error · OidcException
Userinfo endpoint response validation failed with error: {$e
Error message
Userinfo endpoint response validation failed with error: {$exception->getMessage()} What it means
When the userinfo endpoint is used, BookStack validates the userinfo response against the ID token's 'sub' and the configured client_id via OidcUserinfoResponse::validate(). If that raises OidcInvalidTokenException, it is wrapped in this OidcException so the operator sees which userinfo validation failed.
Source
Thrown at app/Access/Oidc/OidcService.php:270
$idToken,
$this->config()['external_id_claim'],
$this->config()['display_name_claims'] ?? '',
$this->config()['groups_claim'] ?? ''
);
if (!$userDetails->isFullyPopulated($this->shouldSyncGroups()) && !empty($settings->userinfoEndpoint)) {
$provider = $this->getProvider($settings);
$request = $provider->getAuthenticatedRequest('GET', $settings->userinfoEndpoint, $accessToken->getToken());
$response = new OidcUserinfoResponse(
$provider->getResponse($request),
$settings->issuer,
$settings->keys,
);
try {
$response->validate($idToken->getClaim('sub'), $settings->clientId);
} catch (OidcInvalidTokenException $exception) {
throw new OidcException("Userinfo endpoint response validation failed with error: {$exception->getMessage()}");
}
$userDetails->populate(
$response,
$this->config()['external_id_claim'],
$this->config()['display_name_claims'] ?? '',
$this->config()['groups_claim'] ?? ''
);
}
return $userDetails;
}
/**
* Get the OIDC config from the application.
*/
protected function config(): array
{View on GitHub (pinned to 18f8469a1c)
Solutions
- Check the wrapped message: it distinguishes 'No valid subject value' from 'Subject value ... does not match'
- Ensure the IdP returns the same 'sub' in userinfo and ID token (disable pairwise/subject-per-client settings if needed)
- Update the IdP or switch to a spec-compliant provider version
- Verify no reverse proxy is altering the userinfo response body
- If userinfo is unnecessary, disable it (remove userinfo endpoint config) so details come from the ID token only
Defensive patterns
Strategy: validation
Validate before calling
// Verify userinfo vs ID token sub before calling the API:
$ui = json_decode(file_get_contents($userinfoUrl, false, stream_context_create(['http' => ['header' => "Authorization: Bearer $at\r\n"]])), true);
$idTokenClaims = json_decode(base64_decode(explode('.', $idToken)[1]), true);
if (!isset($ui['sub']) || !is_string($ui['sub']) || $ui['sub'] !== $idTokenClaims['sub']) {
// IdP is misbehaving — fix subject type / disable userinfo
} Try / catch
try {
auth()->attemptOidcLogin();
} catch (BookStack\Access\Oidc\OidcException $e) {
if (str_contains($e->getMessage(), 'Userinfo endpoint response validation failed')) {
abort(502, 'IdP userinfo response failed validation — check pairwise/public subject settings');
}
throw $e;
} Prevention
- Use 'public' subject type so userinfo and ID token subs match
- Avoid proxies that rewrite/transform IdP JSON responses
- Test with a raw curl userinfo call during IdP setup
- Disable the userinfo endpoint if ID-token claims suffice
When it happens
Trigger: getUserDetailsFromToken fetches the userinfo response, then $response->validate($idToken->getClaim('sub'), $settings->clientId) fails — typically subject mismatch between userinfo and ID token, or missing/invalid sub in the userinfo payload.
Common situations: Misbehaving or misconfigured IdP returning a different subject in userinfo vs ID token (e.g. pairwise subject identifiers or per-client sub values), a proxy/gateway rewriting responses, or an IdP not OIDC-spec compliant (missing sub).
Related errors
- Token audience value has ' . count($aud) . ' values, Expecte
- Token authorized party exists but does not match the expecte
- Missing token expiration time value
- Token has expired
- Missing token issued at time value
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/7e278158253f3ff7.
Report an issue: GitHub.