zed-industries/zed · error

Could not fetch Authorization Server Metadata for {}

Error message

Could not fetch Authorization Server Metadata for {}

What it means

Discovery failed at the second stage: none of the Authorization Server Metadata candidate URLs (RFC 8414 /oauth-authorization-server well-known and OIDC Discovery /.well-known/openid-configuration, in MCP-spec priority order) could be fetched successfully. As with error 167, each individual failure is only logged at debug level and the final bail names just the issuer, so the root cause (DNS, TLS, 404, non-JSON, or an issuer-mismatch bail swallowed by the loop) requires debug logs to see. Note that a candidate can 'fail' via the issuer-mismatch bail in the Ok arm, which is caught by this same loop and retried on the next candidate before giving up.

Source

Thrown at crates/context_server/src/oauth.rs:847

                        .ok_or_else(|| anyhow!("missing authorization_endpoint"))?,
                    token_endpoint: response
                        .token_endpoint
                        .ok_or_else(|| anyhow!("missing token_endpoint"))?,
                    registration_endpoint: response.registration_endpoint,
                    scopes_supported: response.scopes_supported,
                    code_challenge_methods_supported: response.code_challenge_methods_supported,
                    client_id_metadata_document_supported: response
                        .client_id_metadata_document_supported
                        .unwrap_or(false),
                });
            }
            Err(err) => {
                log::debug!("Failed to fetch Auth Server Metadata from {}: {}", url, err);
            }
        }
    }

    bail!(
        "Could not fetch Authorization Server Metadata for {}",
        issuer
    )
}

/// Run the full discovery flow: fetch resource metadata, then auth server
/// metadata, then select scopes. Client registration is resolved separately,
/// once the real redirect URI is known.
pub async fn discover(
    http_client: &Arc<dyn HttpClient>,
    server_url: &Url,
    www_authenticate: &WwwAuthenticate,
) -> Result<OAuthDiscovery> {
    let resource_metadata =
        fetch_protected_resource_metadata(http_client, server_url, www_authenticate).await?;

    let auth_server_url = resource_metadata
        .authorization_servers

View on GitHub (pinned to f4178619ac)

Solutions

  1. Verify the auth server serves metadata at either /.well-known/oauth-authorization-server or /.well-known/openid-configuration for the exact issuer path (curl both)
  2. Correct the authorization_servers entry in the Protected Resource Metadata so it names the real authorization server issuer
  3. Ensure the endpoint returns JSON with 200 and no auth wall; allowlist it in the proxy/SSO layer
  4. Turn on debug logging to see each candidate URL and its specific error before changing configuration

Example fix

# before: issuer points at the resource, auth metadata 404s
"authorization_servers": ["https://mcp.example.com"]

# after: issuer points at the actual authorization server
"authorization_servers": ["https://auth.example.com"]
# where https://auth.example.com/.well-known/openid-configuration returns 200 JSON
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight both discovery endpoint styles for the issuer
async fn as_metadata_reachable(http: &Arc<dyn HttpClient>, issuer: &Url) -> bool {
    auth_server_metadata_urls(issuer).iter().any(|u| {
        fetch_json::<serde_json::Value>(http, u).await.is_ok()
    })
}

Try / catch

match fetch_auth_server_metadata(&client, &issuer).await {
    Ok(meta) => Ok(meta),
    Err(err) if err.to_string().contains("Could not fetch Authorization Server Metadata") => {
        // candidates: /oauth-authorization-server and /openid-configuration; curl them to see which failed and why
        if is_transient_network(&err) { retry_with_backoff().await } else { Err(err) }
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: fetch_auth_server_metadata() iterates auth_server_metadata_urls(issuer); every fetch_json call returns Err — connection refused, 404 for both endpoint styles, HTML instead of JSON, or the Ok branch bailing on issuer mismatch for each candidate.

Common situations: Authorization server that is a plain OAuth2 server without OIDC discovery and without RFC 8414 endpoints; auth server behind auth-offloading proxy that returns an HTML login page on the well-known path; wrong issuer listed in authorization_servers (points at resource not auth server); network egress blocked to the auth domain.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/0842668fa6a36084. Report an issue: GitHub.