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
- Verify the discovery URL is correct by opening it in a browser or curl — it must return the openid-configuration JSON.
- Check network reachability from the Elsa host (DNS, proxy, firewall, egress rules) to the identity provider.
- Confirm TLS trust: a self-signed or private-CA certificate on the provider will make the request fail; install the CA chain.
- 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
- Pre-flight check the discovery URL from the Elsa host before saving the connection.
- Configure proxies/firewall egress to the identity provider authority.
- Install private CA certificates in the host trust store for TLS.
- Use Manual trust mode with explicit endpoints when discovery is unavailable.
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
- The identity provider signing keys could not be resolved.
- The OpenID Connect discovery URL is required.
- The identity provider token exchange failed.
- The identity provider did not provide signing keys.
- Timeout
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).AbsoluteUriView on GitHub (pinned to fe9217bdfa)