alibaba/nacos · error · IOException

Failed to discover OIDC configuration, status:

Error message

Failed to discover OIDC configuration, status: 

What it means

Thrown when the OIDC discovery HTTP GET to <issuer-uri>/.well-known/openid-configuration returns a non-200 status code. The actual status code is appended. This is an IdP-side or connectivity failure, not a Nacos config error (the URL was buildable).

Source

Thrown at plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/config/OidcProviderMetadataProvider.java:95

        return result;
    }
    
    @SuppressWarnings("unchecked")
    private OidcProviderMetadata discover() throws IOException {
        String issuerUri = config.getIssuerUri();
        if (StringUtils.isBlank(issuerUri)) {
            throw new IOException("Issuer URI is not configured");
        }
        String discoveryUrl = trimTrailingSlash(issuerUri)
            + OidcProtocolConstants.WELL_KNOWN_PATH;
        LOGGER.info("Discovering OIDC configuration from: {}", discoveryUrl);
        try {
            HttpRequest request = HttpRequest.newBuilder().uri(URI.create(discoveryUrl))
                .header("Accept", "application/json").timeout(DISCOVERY_TIMEOUT).GET().build();
            HttpResponse<String> response =
                httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() != OidcProtocolConstants.HTTP_STATUS_OK) {
                throw new IOException("Failed to discover OIDC configuration, status: "
                    + response.statusCode());
            }
            Map<String, Object> values = JsonUtils.toObj(response.body(), Map.class);
            if (values == null) {
                throw new IOException("OIDC discovery response is empty");
            }
            OidcProviderMetadata result = new OidcProviderMetadata(
                stringValue(values, OidcProtocolConstants.DISCOVERY_AUTHORIZATION_ENDPOINT),
                stringValue(values, OidcProtocolConstants.DISCOVERY_TOKEN_ENDPOINT),
                stringValue(values, OidcProtocolConstants.DISCOVERY_USERINFO_ENDPOINT),
                stringValue(values, OidcProtocolConstants.DISCOVERY_END_SESSION_ENDPOINT),
                stringValue(values, OidcProtocolConstants.DISCOVERY_JWKS_URI));
            LOGGER.info("OIDC configuration discovered: jwksUri={}", result.getJwksUri());
            return result;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("OIDC discovery interrupted", e);
        } catch (IOException e) {

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. curl the discovery URL yourself and read the appended status code: GET <issuer-uri>/.well-known/openid-configuration.
  2. For 404: correct issuer-uri to the OIDC issuer root (often the realm base URL for Keycloak).
  3. For 5xx: check IdP health and any reverse proxy between Nacos and the IdP.
  4. For 401/403: ensure the discovery endpoint is public per OIDC spec, or whitelist Nacos.
  5. Verify outbound HTTPS connectivity and DNS resolution from the Nacos host.

Example fix

// before: issuer path has no discovery doc (returns 404)
nacos.plugin.auth.oidc.issuer-uri=https://keycloak.example.com
// after: point at the realm root that serves .well-known/openid-configuration
nacos.plugin.auth.oidc.issuer-uri=https://keycloak.example.com/realms/myrealm
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: probe the discovery URL reachability before relying on it
String url = issuerUri.replaceAll("/+$", "") + "/.well-known/openid-configuration";
// (manual curl or an HttpClient probe returning the status code)

Try / catch

try {
    metadataProvider.getMetadata();
} catch (IOException e) {
    if (e.getMessage().contains("status:")) {
        // transient IdP/network issue — back off and retry a limited number of times
        log.warn("OIDC discovery returned non-200; will retry: {}", e.getMessage());
        retryWithBackoff(() -> metadataProvider.getMetadata(), 3);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: getMetadata() triggers discover(); the discovery endpoint responds 404 (wrong issuer path), 401/403 (auth-required discovery), 500 (IdP error), or the host returns a redirect/gateway error.

Common situations: issuer-uri points to a path where discovery doesn't exist (404); IdP is down or behind a misconfigured proxy (502/503); discovery endpoint requires authentication; corporate proxy/firewall blocks the outbound request.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/1b966e0acf0bb26a. Report an issue: GitHub.