{"record":{"id":"a5a6c86f7c01e9ea","repo":"BookStackApp/BookStack","slug":"unexpected-issuer-value-found-on-discovery-respons","errorCode":null,"errorMessage":"Unexpected issuer value found on discovery response","messagePattern":"Unexpected issuer value found on discovery response","errorType":"exception","errorClass":"OidcIssuerDiscoveryException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcProviderSettings.php","lineNumber":126,"sourceCode":"    }\n\n    /**\n     * @throws OidcIssuerDiscoveryException\n     * @throws ClientExceptionInterface\n     */\n    protected function loadSettingsFromIssuerDiscovery(ClientInterface $httpClient): array\n    {\n        $issuerUrl = rtrim($this->issuer, '/') . '/.well-known/openid-configuration';\n        $request = new Request('GET', $issuerUrl);\n        $response = $httpClient->sendRequest($request);\n        $result = json_decode($response->getBody()->getContents(), true);\n\n        if (empty($result) || !is_array($result)) {\n            throw new OidcIssuerDiscoveryException(\"Error discovering provider settings from issuer at URL {$issuerUrl}\");\n        }\n\n        if ($result['issuer'] !== $this->issuer) {\n            throw new OidcIssuerDiscoveryException('Unexpected issuer value found on discovery response');\n        }\n\n        $discoveredSettings = [];\n\n        if (!empty($result['authorization_endpoint'])) {\n            $discoveredSettings['authorizationEndpoint'] = $result['authorization_endpoint'];\n        }\n\n        if (!empty($result['token_endpoint'])) {\n            $discoveredSettings['tokenEndpoint'] = $result['token_endpoint'];\n        }\n\n        if (!empty($result['userinfo_endpoint'])) {\n            $discoveredSettings['userinfoEndpoint'] = $result['userinfo_endpoint'];\n        }\n\n        if (!empty($result['jwks_uri'])) {\n            $keys = $this->loadKeysFromUri($result['jwks_uri'], $httpClient);","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcProviderSettings.php#L108-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nOIDC_ISSUER=https://idp.example.com/realms/wrong\n# after (must equal the 'issuer' claim in discovery JSON)\nOIDC_ISSUER=https://idp.example.com/realms/main","handlingStrategy":"validation","validationCode":"$doc = json_decode(file_get_contents($discoveryUrl), true);\nif (($doc['issuer'] ?? null) !== config('oidc.issuer')) {\n    throw new RuntimeException('Configured issuer does not match discovery issuer claim: ' . ($doc['issuer'] ?? 'null'));\n}","typeGuard":null,"tryCatchPattern":"try {\n    $settings->discoverFromIssuer($client, $cache, 15);\n} catch (OidcIssuerDiscoveryException $e) {\n    if (str_contains($e->getMessage(), 'Unexpected issuer')) {\n        Log::error('Issuer mismatch — compare configured issuer with discovery document');\n    }\n}","preventionTips":["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."],"tags":["oidc","discovery","issuer-mismatch","configuration"],"backgroundTag":"issuer-mismatch","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}