{"record":{"id":"a12bcbfc9c22b68d","repo":"elsa-workflows/elsa-core","slug":"the-openid-connect-discovery-url-is-required","errorCode":null,"errorMessage":"The OpenID Connect discovery URL is required.","messagePattern":"The OpenID Connect discovery URL is required\\.","errorType":"exception","errorClass":"OpenIdConnectAuthenticationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectExternalAuthenticationAdapter.cs","lineNumber":141,"sourceCode":"        if (context.UpstreamLogoutHint is not null)\n            query[\"id_token_hint\"] = context.UpstreamLogoutHint.Reveal();\n        return new(WithQuery(metadata.EndSessionEndpoint, query), []);\n    }\n\n    private async Task<OpenIdConnectConnectionSettings> GetSettingsAsync(JsonElement settings, CancellationToken cancellationToken)\n    {\n        if (!settingsParser.TryParse(settings, out var parsed, out _))\n            throw new OpenIdConnectAuthenticationException(\"The OpenID Connect connection configuration is invalid.\");\n        await Task.CompletedTask;\n        return parsed!;\n    }\n\n    private async Task<ProviderMetadata> ResolveMetadataAsync(OpenIdConnectConnectionSettings settings, CancellationToken cancellationToken)\n    {\n        if (settings.TrustMode == OpenIdConnectTrustMode.Manual)\n            return new(settings.Issuer!, settings.AuthorizationEndpoint!, settings.TokenEndpoint!, settings.UserInfoEndpoint, settings.EndSessionEndpoint, settings.JwksUri, settings.SigningKeys);\n\n        var address = settings.DiscoveryUrl ?? throw new OpenIdConnectAuthenticationException(\"The OpenID Connect discovery URL is required.\");\n        var response = await providerHttpClient.GetAsync(address, ProviderResponseKind.Discovery, cancellationToken);\n        if (!response.IsSuccessStatusCode)\n            throw new OpenIdConnectAuthenticationException(\"The identity provider metadata could not be resolved.\");\n        using var document = ParseProviderJson(response.Body, \"The identity provider metadata could not be resolved.\");\n        var root = document.RootElement;\n        var issuer = GetRequiredHttpsUri(root, \"issuer\").AbsoluteUri.TrimEnd('/');\n        var authorizationEndpoint = GetRequiredHttpsUri(root, \"authorization_endpoint\");\n        var tokenEndpoint = GetRequiredHttpsUri(root, \"token_endpoint\");\n        return new(issuer, authorizationEndpoint, tokenEndpoint, GetOptionalHttpsUri(root, \"userinfo_endpoint\"), GetOptionalHttpsUri(root, \"end_session_endpoint\"), GetOptionalHttpsUri(root, \"jwks_uri\"), default);\n    }\n\n    private async Task<string> ExchangeCodeAsync(OpenIdConnectConnectionSettings settings, ProviderMetadata metadata, ExternalCallbackContext context, string? verifier, CancellationToken cancellationToken)\n    {\n        if (!TryGetParameter(context.Parameters, \"code\", out var code))\n            throw new OpenIdConnectAuthenticationException(\"The identity provider callback did not contain an authorization code.\");\n\n        var values = new Dictionary<string, string>\n        {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectExternalAuthenticationAdapter.cs#L123-L159","documentation":"ResolveMetadataAsync only fetches a discovery document when TrustMode is not Manual. In discovery mode, settings.DiscoveryUrl is the source of the provider metadata; if it is null, the adapter cannot discover the provider and throws this exception instead of attempting an HTTP request.","triggerScenarios":"Calling ResolveMetadataAsync (via initiation, callback, or TestAsync) with settings.TrustMode != Manual and settings.DiscoveryUrl unset.","commonSituations":"Creating a connection and choosing discovery-based trust but forgetting to fill in the discovery URL; copying a Manual-mode template into a discovery-mode connection.","solutions":["Set discoveryUrl in the connection settings (typically https://<authority>/.well-known/openid-configuration).","Alternatively switch trustMode to \"Manual\" and provide issuer, authorizationEndpoint and tokenEndpoint explicitly.","Re-test the connection with TestAsync after fixing the settings."],"exampleFix":"// before\n{ \"trustMode\": \"Discovery\", \"clientId\": \"my-client\" }\n// after\n{ \"trustMode\": \"Discovery\", \"discoveryUrl\": \"https://idp.example.com/.well-known/openid-configuration\", \"clientId\": \"my-client\" }","handlingStrategy":"validation","validationCode":"if (settings.TrustMode != \"Manual\" && string.IsNullOrWhiteSpace(settings.DiscoveryUrl)) throw new InvalidOperationException(\"Discovery trust mode requires a discoveryUrl.\");","typeGuard":null,"tryCatchPattern":"try { await adapter.TestAsync(testContext); } catch (OpenIdConnectAuthenticationException ex) when (ex.Message.Contains(\"discovery URL is required\")) { return Results.ValidationProblem(new Dictionary<string, string[]> { [\"discoveryUrl\"] = [\"Discovery URL is required for discovery trust mode.\"] }); }","preventionTips":["Enforce discoveryUrl as a required field in your connection editor when trustMode is not Manual.","Default discoveryUrl to <authority>/.well-known/openid-configuration when the user supplies only an authority.","Run the connection TestAsync immediately after saving settings."],"tags":["openid-connect","configuration","discovery"],"backgroundTag":"missing-required-config-field","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}