{"record":{"id":"bbe3074ccd472557","repo":"elsa-workflows/elsa-core","slug":"the-identity-provider-signing-keys-could-not-be-resolved","errorCode":null,"errorMessage":"The identity provider signing keys could not be resolved.","messagePattern":"The identity provider signing keys could not be resolved\\.","errorType":"exception","errorClass":"OpenIdConnectAuthenticationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectExternalAuthenticationAdapter.cs","lineNumber":232,"sourceCode":"    private Uri GetCallbackUri(EffectiveIdentityProviderConnection connection, BrokerTransactionPurpose purpose)\n    {\n        var baseUri = options.Value.Redirects.ExternalCallbackBaseUri ?? throw new OpenIdConnectAuthenticationException(\"The deployment callback base URI is not configured.\");\n        return ExternalAuthenticationCallbackUris.GetAuthorizationCallbackUri(baseUri, connection.Connection, purpose);\n    }\n\n    private Uri GetLogoutCallbackUri(EffectiveIdentityProviderConnection connection)\n    {\n        var baseUri = options.Value.Redirects.ExternalCallbackBaseUri ?? throw new OpenIdConnectAuthenticationException(\"The deployment callback base URI is not configured.\");\n        return ExternalAuthenticationCallbackUris.GetLogoutCallbackUri(baseUri, connection.Connection.Key);\n    }\n\n    private async Task<IEnumerable<SecurityKey>> GetSigningKeysAsync(Uri? jwksUri, CancellationToken cancellationToken)\n    {\n        if (jwksUri is null)\n            throw new OpenIdConnectAuthenticationException(\"The identity provider did not provide signing keys.\");\n        var response = await providerHttpClient.GetAsync(jwksUri, ProviderResponseKind.SigningKeys, cancellationToken);\n        if (!response.IsSuccessStatusCode)\n            throw new OpenIdConnectAuthenticationException(\"The identity provider signing keys could not be resolved.\");\n        try\n        {\n            return new JsonWebKeySet(response.ReadBodyAsUtf8()).Keys;\n        }\n        catch (JsonException)\n        {\n            throw new OpenIdConnectAuthenticationException(\"The identity provider signing keys were invalid.\");\n        }\n    }\n\n    private static IReadOnlyDictionary<string, IReadOnlyCollection<string>> ProjectClaims(System.Security.Claims.ClaimsPrincipal principal, ClaimProjection projection)\n    {\n        if (projection.MaximumClaimCount <= 0 || projection.MaximumValueLength <= 0 || projection.MaximumTotalBytes <= 0)\n            return new Dictionary<string, IReadOnlyCollection<string>>(StringComparer.Ordinal);\n\n        var allowed = projection.AllowedClaimTypes ?? new HashSet<string>();\n        var result = new Dictionary<string, List<string>>(StringComparer.Ordinal);\n        var count = 0;","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Services/OpenIdConnectExternalAuthenticationAdapter.cs#L214-L250","documentation":"The JWKS URI exists and was fetched, but the HTTP response was not successful, so signing keys could not be downloaded. ID-token signature validation cannot proceed without keys. The underlying status code is not embedded in the message, so check provider availability and network path.","triggerScenarios":"GetSigningKeysAsync's providerHttpClient.GetAsync to the jwks_uri returns a non-2xx status: 404 (wrong jwks path), 403 (WAF/IP blocking), 5xx (provider outage), or connection-level failure surfaced as non-success.","commonSituations":"Server cannot reach the identity provider (egress firewall, private IDP not routable from the app host); TLS trust issues terminating as failed fetches; provider temporarily down during key rotation; self-hosted Keycloak behind a proxy returning 404 for /.well-known/jwks.json.","solutions":["Confirm the app host can reach the jwks_uri (curl it from the server; check DNS, proxy, and firewall/egress rules).","Check the returned status code via provider/proxy logs to distinguish 404 vs 403 vs 5xx.","Fix TLS trust (install the provider's CA chain into the host trust store) if the fetch fails on certificate validation.","Add retry with backoff for transient 5xx during provider key rotation windows.","Verify the jwks_uri path in the discovery document matches the provider's actual JWKS route."],"exampleFix":"// before: IDP not reachable from container\nissuer: \"https://internal-idp.local\"  // resolvable only on the corporate LAN\n// after: ensure egress DNS/route or use a reachable address\nissuer: \"https://idp.internal.example.com\" // with DNS + firewall entry for the app host","handlingStrategy":"retry","validationCode":"using var ping = await httpClient.GetAsync(jwksUri, HttpCompletionOption.ResponseHeadersRead, ct);\nif (!ping.IsSuccessStatusCode)\n    throw new InvalidOperationException($\"JWKS endpoint {jwksUri} returned {ping.StatusCode}; fix reachability before sign-in.\");","typeGuard":null,"tryCatchPattern":"try { await adapter.ValidateIdTokenAsync(idToken, settings, metadata, ct); }\ncatch (OpenIdConnectAuthenticationException ex) when (ex.Message.Contains(\"could not be resolved\"))\n{\n    await Task.Delay(TimeSpan.FromSeconds(2), ct); // retry once for transient provider unavailability\n    // retry the flow or return 502\n    return Results.Problem(\"Identity provider signing keys are temporarily unavailable.\", statusCode: 502);\n}","preventionTips":["Verify egress firewall/DNS allows the app host to reach the provider's jwks_uri","Install the provider's TLS CA chain on the host","Monitor the JWKS endpoint with a health probe","Retry with backoff only on 5xx, never on 4xx"],"tags":["network","openid-connect","jwks","http","identity-provider"],"backgroundTag":"http-error-response","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"}