'System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String' with .NET 5

I've been implementing IdentityServer4 to provide authorization for my React application. I have this working in my local dev environment, but am running into issues after deployed to IIS in Windows Server 2016. I am able to generate an access token via the /connect/token endpoint, but when I attempt to access a protected API using the token I get the following exception:

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
 ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
 ---> System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (dev-drydata-auth.universal-compliance.com:443)
 ---> System.Net.Sockets.SocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|283_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.DefaultConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
   at System.Net.Http.ConnectHelper.ConnectAsync(Func`3 callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(Func`3 callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.RedirectToIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context)
   at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
   at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()

My ConfigureServices as follows:

public void ConfigureServices(IServiceCollection services)
{
    ConfigureDryDataServices(services);

    services.AddControllersWithViews();

    services.AddCors(options =>
    {
        options.AddPolicy("AllOrigins",
        builder =>
        {
            builder.AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowAnyOrigin();

        });
    });
    services.AddScoped<IClaimsTransformation, WebAppCalimsTransformation>();
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(o =>
    {
        o.Authority = Configuration.GetValue<string>("AppSettings:Auth:ServerUrl");
        o.Audience = Configuration.GetValue<string>("AppSettings:Auth:Audience");
        o.RequireHttpsMetadata = false;
        o.Events = new JwtBearerEvents
        {
            OnTokenValidated = context =>
            {
                if (context.SecurityToken is JwtSecurityToken accessToken && context.Principal.Identity is ClaimsIdentity identity)
                {
                    identity.AddClaim(new Claim("access_token", accessToken.RawData));
                }

                return Task.CompletedTask;
            }
        };
    });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("ApiReader", policy => policy.RequireClaim("scope", "my_api_software"));
        options.AddPolicy("admin", policy => policy.RequireClaim(ClaimTypes.Role, "admin"));
        options.AddPolicy("user", policy => policy.RequireClaim(ClaimTypes.Role, "user"));
    });

    services.AddHttpClient("Auth", config =>
    {
        config.BaseAddress = new Uri(Configuration.GetValue<string>("AppSettings:Auth:ServerUrl"));
    });

    // In production, the React files will be served from this directory
    services.AddSpaStaticFiles(configuration =>
    {
        configuration.RootPath = "ClientApp/build";
    });


    services.AddSwaggerDocument(config => {
        config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
        config.AddSecurity("JWT token", new OpenApiSecurityScheme
        {
            Type = OpenApiSecuritySchemeType.ApiKey,
            Name = "Authorization",
            Description = "Copy 'Bearer ' + valid JWT token into field",
            In = OpenApiSecurityApiKeyLocation.Header
        });
        config.PostProcess = (document) =>
        {
            document.Info.Version = "v1";
            document.Info.Title = "My API API";
            document.Info.Description = "ASP.NET 5.0 My API";
        };
    });
}

This is also working fine when deploying local IIS in my pc



Solution 1:[1]

The problem is that the API can't reach your IdentityServer from within your deployment, as defined in the code here:

  }).AddJwtBearer(o =>
    {
        o.Authority = Configuration.GetValue<string>("AppSettings:Auth:ServerUrl");
  

So, what you need to do it via networking/dns make sure the Authority in the API is actually reachable from within your server. Even if they are all reachable from your browser, does not mean the API can reach your IdentityServer from within the local network on the server side.

Solution 2:[2]

Just posting this to save someone in the future some time. The problem is that the certificate you are using probably does not have a dns entry for the identityserver or the webapplication address.

You can fix this by creating a certificate with multiple dns addresses.

If you are a visual studio user like me you can easily create a certificate using New-SelfSignedCertificate

Solution 3:[3]

In my case SSL was blocking local access

In terminal

dotnet dev-certs https --trust

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tore Nestenius
Solution 2 John Hardcash
Solution 3 ferdi