Identityserver4: "Unable to obtain configuration from ..." after updating to VS 2017

Created on 9 Mar 2017  路  8Comments  路  Source: IdentityServer/IdentityServer4

After updating to VS 2017 csproj I can no longer access endpoints that require authorization. The error complains about:

Unable to obtain configuration from: 'http://localhost:4000/.well-known/openid-configuration'.

I can access http://localhost:4000/.well-known/openid-configuration from by browser window just fine and see the configuration data.

I can obtain a token just fine.

Issue can be seen on this repo: https://github.com/bitwarden/core

Issue / Steps to reproduce the problem

  • Update project to VS 2017 csproj.
  • Authenticate and gain token.
  • Try to access endpoint protected by [Authorize]

Relevant parts of the log file

The thread 0x10ec has exited with code 0 (0x0).
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET http://localhost:4000/accounts/profile?access_token2={TheToken}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware: Error: Exception occurred while processing message.

System.InvalidOperationException: IDX10803: Unable to obtain configuration from: 'http://localhost:4000/.well-known/openid-configuration'.
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.<GetConfigurationAsync>d__24.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
Microsoft.AspNetCore.Server.Kestrel: Error: Connection id "0HL36HQ41TQMT": An unhandled exception was thrown by the application.

System.InvalidOperationException: IDX10803: Unable to obtain configuration from: 'http://localhost:4000/.well-known/openid-configuration'.
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.<GetConfigurationAsync>d__24.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.<InitializeAsync>d__52.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at IdentityServer4.Hosting.IdentityServerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at IdentityServer4.Hosting.BaseUrlMiddleware.<Invoke>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at AspNetCoreRateLimit.IpRateLimitMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.<RequestProcessingAsync>d__2.MoveNext()
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request finished in 4.7378ms 500 

Most helpful comment

So after an inviting session of impaling my head on the corner of a wall, I realized it was a simple oversight on my part. It's truly spectacular the revelations blunt force trauma can inspire. So here's my story.

My authorization server and my API were running in separate local Docker containers spun up with docker-compose. I ran my test client console application on my local machine. My API container was exposing a few ports, and I could access the API by navigating to a URL like http://api.dev.domain.org. Thinking nothing of it, I had my API configured to look for the authentication server at http://api.dev.domain.org:5000 as seen below. This meant my API would look for the discovery document at http://api.dev.domain.org:5000/.well-known/openid-configuration. Note that my discovery document is hosted on port 5000.

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAuthentication()
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "http://api.dev.domain.org:5000";
            options.RequireHttpsMetadata = false;
            options.ApiName = "ApiName";
        });
    ...
}

__What took me so long to realize was http://api.dev.domain.org resolved to http://localhost.__ Recall my API was in a Docker container so this was resolving to http://localhost in that Docker container which was not responsible for hosting the discovery document.

To what could I change it? The container in which my authentication server was running was called auth, so, courtesy of docker-compose wizardry, I changed the authority to http://auth. Note that my authentication server was running on port 80 in the container.

Fortunately, my API could now read the discovery document, but my test client was failing - something along the lines of The host http://api.dev.domain:5000 does not match trusted host http://auth. I'm paraphrasing, but you should be picking up what I'm putting down. Note that my test client made use of the discovery document endpoint as seen below.

var discoveryClient = new DiscoveryClient("http://api.dev.domain.org:5000");
discoveryClient.Policy.RequireHttps = false;
var discovery = await discoveryClient.GetAsync();

__My conclusion was this: my authentication server needed to be referenced identically in my test client and API.__ So I took a step back. My test client really had no other option but to refer to my authentication server as http://api.dev.domain.org:5000. That was the only address the container exposed. With that in mind, I reverted my change to the API and returned the authority to http://api.dev.domain.org:5000.

__I'm not sure how I feel about what follows.__

I changed the name of the authentication server Docker container in my docker-compose.yml file to auth.dev.domain.org. I then changed my API authority to http://auth.dev.domain.org:5000, and changed my endpoint in my test client to http://auth.dev.domain.org:5000. While these strings are identical, they technically refer to the names of two different things. The authority in my API refers to the actual name of the authentication server Docker container. The endpoint in my test client refers to the resolved hostname exposed by said container.

That's my story. Cheers.

All 8 comments

I'm getting the same error on our Test server but it works fine for me locally.

Maybe related: https://github.com/aspnet/Security/issues/1116

I'll test that possible fix tonight.

Yes, they suggest upgrading to System.Net.Http v4.3.1. Am in the middle of doing so. I'd advise closing this duplicate issue.

I was able to resolve this as suggested in https://github.com/aspnet/Security/issues/1116 by updating to System.Net.Http v4.3.1

I am facing the exact same error. I have tried System.Net.Http v4.3.3 and System.Net.Http v4.3.1.

@JakeKo me too. Having the same issue. Identity server is using net471 and client with netcoreapp2.1

So after an inviting session of impaling my head on the corner of a wall, I realized it was a simple oversight on my part. It's truly spectacular the revelations blunt force trauma can inspire. So here's my story.

My authorization server and my API were running in separate local Docker containers spun up with docker-compose. I ran my test client console application on my local machine. My API container was exposing a few ports, and I could access the API by navigating to a URL like http://api.dev.domain.org. Thinking nothing of it, I had my API configured to look for the authentication server at http://api.dev.domain.org:5000 as seen below. This meant my API would look for the discovery document at http://api.dev.domain.org:5000/.well-known/openid-configuration. Note that my discovery document is hosted on port 5000.

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAuthentication()
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "http://api.dev.domain.org:5000";
            options.RequireHttpsMetadata = false;
            options.ApiName = "ApiName";
        });
    ...
}

__What took me so long to realize was http://api.dev.domain.org resolved to http://localhost.__ Recall my API was in a Docker container so this was resolving to http://localhost in that Docker container which was not responsible for hosting the discovery document.

To what could I change it? The container in which my authentication server was running was called auth, so, courtesy of docker-compose wizardry, I changed the authority to http://auth. Note that my authentication server was running on port 80 in the container.

Fortunately, my API could now read the discovery document, but my test client was failing - something along the lines of The host http://api.dev.domain:5000 does not match trusted host http://auth. I'm paraphrasing, but you should be picking up what I'm putting down. Note that my test client made use of the discovery document endpoint as seen below.

var discoveryClient = new DiscoveryClient("http://api.dev.domain.org:5000");
discoveryClient.Policy.RequireHttps = false;
var discovery = await discoveryClient.GetAsync();

__My conclusion was this: my authentication server needed to be referenced identically in my test client and API.__ So I took a step back. My test client really had no other option but to refer to my authentication server as http://api.dev.domain.org:5000. That was the only address the container exposed. With that in mind, I reverted my change to the API and returned the authority to http://api.dev.domain.org:5000.

__I'm not sure how I feel about what follows.__

I changed the name of the authentication server Docker container in my docker-compose.yml file to auth.dev.domain.org. I then changed my API authority to http://auth.dev.domain.org:5000, and changed my endpoint in my test client to http://auth.dev.domain.org:5000. While these strings are identical, they technically refer to the names of two different things. The authority in my API refers to the actual name of the authentication server Docker container. The endpoint in my test client refers to the resolved hostname exposed by said container.

That's my story. Cheers.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings