BookStackApp/BookStack · error · OidcIssuerDiscoveryException
Unexpected issuer value found on discovery response
Error message
Unexpected issuer value found on discovery response
What it means
After decoding the discovery document, loadSettingsFromIssuerDiscovery() compares the document's 'issuer' claim with the configured issuer and throws OidcIssuerDiscoveryException if they differ. OIDC requires an exact match; a mismatch means the document may belong to a different tenant/realm or a man-in-the-middle.
Source
Thrown at app/Access/Oidc/OidcProviderSettings.php:126
}
/**
* @throws OidcIssuerDiscoveryException
* @throws ClientExceptionInterface
*/
protected function loadSettingsFromIssuerDiscovery(ClientInterface $httpClient): array
{
$issuerUrl = rtrim($this->issuer, '/') . '/.well-known/openid-configuration';
$request = new Request('GET', $issuerUrl);
$response = $httpClient->sendRequest($request);
$result = json_decode($response->getBody()->getContents(), true);
if (empty($result) || !is_array($result)) {
throw new OidcIssuerDiscoveryException("Error discovering provider settings from issuer at URL {$issuerUrl}");
}
if ($result['issuer'] !== $this->issuer) {
throw new OidcIssuerDiscoveryException('Unexpected issuer value found on discovery response');
}
$discoveredSettings = [];
if (!empty($result['authorization_endpoint'])) {
$discoveredSettings['authorizationEndpoint'] = $result['authorization_endpoint'];
}
if (!empty($result['token_endpoint'])) {
$discoveredSettings['tokenEndpoint'] = $result['token_endpoint'];
}
if (!empty($result['userinfo_endpoint'])) {
$discoveredSettings['userinfoEndpoint'] = $result['userinfo_endpoint'];
}
if (!empty($result['jwks_uri'])) {
$keys = $this->loadKeysFromUri($result['jwks_uri'], $httpClient);View on GitHub (pinned to 18f8469a1c)
Solutions
- Open the discovery URL and copy the exact 'issuer' value into OIDC_ISSUER verbatim.
- Check scheme/port/path differences caused by a reverse proxy; set the IdP's public/frontend URL so its advertised issuer matches what BookStack uses.
- Clear the 'oidc-discovery::<issuer>' cache entry after correcting the value.
- Confirm you're pointing at the intended realm/tenant, not a sibling one.
Example fix
# before OIDC_ISSUER=https://idp.example.com/realms/wrong # after (must equal the 'issuer' claim in discovery JSON) OIDC_ISSUER=https://idp.example.com/realms/main
Defensive patterns
Strategy: validation
Validate before calling
$doc = json_decode(file_get_contents($discoveryUrl), true);
if (($doc['issuer'] ?? null) !== config('oidc.issuer')) {
throw new RuntimeException('Configured issuer does not match discovery issuer claim: ' . ($doc['issuer'] ?? 'null'));
} Try / catch
try {
$settings->discoverFromIssuer($client, $cache, 15);
} catch (OidcIssuerDiscoveryException $e) {
if (str_contains($e->getMessage(), 'Unexpected issuer')) {
Log::error('Issuer mismatch — compare configured issuer with discovery document');
}
} Prevention
- Copy the 'issuer' claim from the discovery document verbatim into OIDC_ISSUER.
- Fix the IdP's public/base URL so its advertised issuer matches external access (proxy/TLS offloading).
- Beware trailing slashes and realm paths — the comparison is exact.
- Clear discovery cache after changing the issuer.
When it happens
Trigger: Configured OIDC_ISSUER differs from the 'issuer' field in the fetched /.well-known/openid-configuration — typically by scheme, port, trailing path, realm name, or http vs https behind a proxy.
Common situations: Keycloak realm path mismatch (issuer without /realms/<name>); IdP behind TLS-offloading proxy advertising https while configured issuer is http (or vice versa); issuer configured with trailing slash while the document has none; pointing at the wrong realm/tenant.
Related errors
- OIDC Discovery Error:
- Failed to read signing key with error:
- Missing or non-matching token issuer value
- Missing required configuration "{$prop}" value
- Issuer value must start with https://
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/a5a6c86f7c01e9ea.
Report an issue: GitHub.