elsa-workflows/elsa-core · error · OpenIdConnectAuthenticationException

The identity provider metadata could not be resolved.

Error message

The identity provider metadata could not be resolved.

What it means

In discovery mode, ResolveMetadataAsync requests the discovery URL through providerHttpClient and checks IsSuccessStatusCode. A non-success response (or unparseable body passed to ParseProviderJson with the same message) yields this exception, meaning the provider's OpenID Connect metadata could not be retrieved.

Solutions

  1. Verify the discovery URL is correct by opening it in a browser or curl — it must return the openid-configuration JSON.
  2. Check network reachability from the Elsa host (DNS, proxy, firewall, egress rules) to the identity provider.
  3. Confirm TLS trust: a self-signed or private-CA certificate on the provider will make the request fail; install the CA chain.
  4. Fall back to TrustMode.Manual with explicit endpoints if discovery is unavailable at the provider.

Example fix

// before
"discoveryUrl": "https://idp.example.com/.well-known/openid-configuration" // host unreachable
// after (manual mode fallback)
{ "trustMode": "Manual", "issuer": "https://idp.example.com", "authorizationEndpoint": "https://idp.example.com/authorize", "tokenEndpoint": "https://idp.example.com/token" }
Defensive patterns

Strategy: retry

Validate before calling

using var http = new HttpClient(); var probe = await http.GetAsync(discoveryUrl); if (!probe.IsSuccessStatusCode) logger.LogError("Discovery endpoint returned {Status}", probe.StatusCode);

Try / catch

try { await adapter.TestAsync(testContext); } catch (OpenIdConnectAuthenticationException ex) when (ex.Message.Contains("metadata could not be resolved")) { logger.LogError(ex, "Discovery fetch failed for {Url}", discoveryUrl); throw; }

Prevention

When it happens

Trigger: ResolveMetadataAsync where providerHttpClient.GetAsync on settings.DiscoveryUrl returns a non-success status, or ParseProviderJson fails on the response body.

Common situations: Wrong discovery URL or typo in the authority; the provider is unreachable (firewall, DNS, private network); discovery endpoint disabled; TLS certificate issues; server returning 500 or 404.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/ac0d7290c131f16c. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectExternalAuthenticationAdapter.cs:144

    }

    private async Task<OpenIdConnectConnectionSettings> GetSettingsAsync(JsonElement settings, CancellationToken cancellationToken)
    {
        if (!settingsParser.TryParse(settings, out var parsed, out _))
            throw new OpenIdConnectAuthenticationException("The OpenID Connect connection configuration is invalid.");
        await Task.CompletedTask;
        return parsed!;
    }

    private async Task<ProviderMetadata> ResolveMetadataAsync(OpenIdConnectConnectionSettings settings, CancellationToken cancellationToken)
    {
        if (settings.TrustMode == OpenIdConnectTrustMode.Manual)
            return new(settings.Issuer!, settings.AuthorizationEndpoint!, settings.TokenEndpoint!, settings.UserInfoEndpoint, settings.EndSessionEndpoint, settings.JwksUri, settings.SigningKeys);

        var address = settings.DiscoveryUrl ?? throw new OpenIdConnectAuthenticationException("The OpenID Connect discovery URL is required.");
        var response = await providerHttpClient.GetAsync(address, ProviderResponseKind.Discovery, cancellationToken);
        if (!response.IsSuccessStatusCode)
            throw new OpenIdConnectAuthenticationException("The identity provider metadata could not be resolved.");
        using var document = ParseProviderJson(response.Body, "The identity provider metadata could not be resolved.");
        var root = document.RootElement;
        var issuer = GetRequiredHttpsUri(root, "issuer").AbsoluteUri.TrimEnd('/');
        var authorizationEndpoint = GetRequiredHttpsUri(root, "authorization_endpoint");
        var tokenEndpoint = GetRequiredHttpsUri(root, "token_endpoint");
        return new(issuer, authorizationEndpoint, tokenEndpoint, GetOptionalHttpsUri(root, "userinfo_endpoint"), GetOptionalHttpsUri(root, "end_session_endpoint"), GetOptionalHttpsUri(root, "jwks_uri"), default);
    }

    private async Task<string> ExchangeCodeAsync(OpenIdConnectConnectionSettings settings, ProviderMetadata metadata, ExternalCallbackContext context, string? verifier, CancellationToken cancellationToken)
    {
        if (!TryGetParameter(context.Parameters, "code", out var code))
            throw new OpenIdConnectAuthenticationException("The identity provider callback did not contain an authorization code.");

        var values = new Dictionary<string, string>
        {
            ["grant_type"] = "authorization_code",
            ["code"] = code,
            ["redirect_uri"] = GetCallbackUri(context.Connection, context.Transaction.Purpose).AbsoluteUri

View on GitHub (pinned to fe9217bdfa)