{"record":{"id":"4dbfb759a3f05ff1","repo":"BookStackApp/BookStack","slug":"error-discovering-provider-settings-from-issuer-at","errorCode":null,"errorMessage":"Error discovering provider settings from issuer at URL {$issuerUrl}","messagePattern":"Error discovering provider settings from issuer at URL (.+?)","errorType":"exception","errorClass":"OidcIssuerDiscoveryException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcProviderSettings.php","lineNumber":122,"sourceCode":"            $this->applySettingsFromArray($discoveredSettings);\n        } catch (ClientExceptionInterface $exception) {\n            throw new OidcIssuerDiscoveryException(\"HTTP request failed during discovery with error: {$exception->getMessage()}\");\n        }\n    }\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'];","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcProviderSettings.php#L104-L140","documentation":"loadSettingsFromIssuerDiscovery() throws this when the response from {issuer}/.well-known/openid-configuration is empty, is not valid JSON, or does not decode to an array. The library therefore received *a* HTTP response but it wasn't a usable discovery document.","triggerScenarios":"The discovery URL returns 200 with non-JSON content (HTML login/error page, empty body, proxy interstitial), or the request was redirected to an SSO sign-in page that returns HTML with status 200.","commonSituations":"Issuer URL wrong so a web server's default page/404 HTML is returned; an auth wall or WAF intercepting the request; gzip/misconfigured proxy returning garbage; hitting a human-facing portal path instead of the real OIDC issuer.","solutions":["curl the discovery URL from the server and inspect the raw body — it must be JSON with issuer, endpoints and jwks_uri.","Correct OIDC_ISSUER so it points to the actual OIDC issuer (e.g. include the realm path in Keycloak: https://host/realms/<realm>).","Bypass or authenticate the proxy/WAF intercepting server-to-server requests, or allowlist the BookStack host.","Verify no redirect to an SSO login page occurs (curl -L and check content-type is application/json)."],"exampleFix":"# before\nOIDC_ISSUER=https://keycloak.example.com  # hits portal HTML\n# after\nOIDC_ISSUER=https://keycloak.example.com/realms/main  # serves JSON discovery","handlingStrategy":"type-guard","validationCode":"$raw = file_get_contents(rtrim(config('oidc.issuer'), '/') . '/.well-known/openid-configuration');\n$doc = json_decode($raw ?? '', true);\nif (!is_array($doc) || empty($doc['issuer'])) {\n    throw new RuntimeException('Discovery endpoint did not return a JSON document');\n}","typeGuard":"function isValidDiscoveryDoc(?array $decoded): bool {\n    return is_array($decoded)\n        && isset($decoded['issuer'], $decoded['authorization_endpoint'], $decoded['token_endpoint']);\n}","tryCatchPattern":"try {\n    $settings->discoverFromIssuer($client, $cache, 15);\n} catch (OidcIssuerDiscoveryException $e) {\n    if (str_contains($e->getMessage(), 'Error discovering provider settings')) {\n        Log::error('Discovery response was not JSON — check issuer URL / auth walls: ' . $e->getMessage());\n    }\n}","preventionTips":["Point the issuer at the real OIDC issuer path, not a portal URL that serves HTML.","Allowlist the BookStack server in any WAF/auth-wall in front of the IdP.","curl -i the discovery URL and confirm content-type application/json before deploying.","Watch for redirects to SSO sign-in pages when fetching discovery server-side."],"tags":["discovery","json","oidc","network"],"backgroundTag":"discovery-document-invalid","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}