I want to be able to authenticate against an Identity Server (STS) from outside and inside a docker machine.
I am having trouble with setting the correct authority that works both inside and outside the container. If I set the authority to the internal name mcoidentityserver:5000
then the API can authenticate but the client cannot get a token as the client lies outside of the docker network. If I set the authority to the external name localhost:5000
then the client can get a token but the API doesn't recognise the authority name (because localhost
in this case is host machine).
What should I set the Authority to? Or perhaps I need to adjust the docker networking?
The red arrow is the part that I'm having trouble with.
I am setting up a Windows 10 docker development environment that uses an ASP.NET Core API (on Linux), Identity Server 4 (ASP.NET Core on Linux) and a PostgreSQL database. PostgreSQL isn't a problem, included in the diagram for completeness. It's mapped to 9876 because I also have a PostgreSQL instance running on the host for now. mco
is a shortened name of our company.
I have been following the Identity Server 4 instructions to get up and running.
I'm not including the docker-compose.debug.yml
because it has run commands pertinent only to running in Visual Studio.
docker-compose.yml
version: '2' services: mcodatabase: image: mcodatabase build: context: ./Data dockerfile: Dockerfile restart: always ports: - 9876:5432 environment: POSTGRES_USER: mcodevuser POSTGRES_PASSWORD: password POSTGRES_DB: mcodev volumes: - postgresdata:/var/lib/postgresql/data networks: - mconetwork mcoidentityserver: image: mcoidentityserver build: context: ./Mco.IdentityServer dockerfile: Dockerfile ports: - 5000:5000 networks: - mconetwork mcoapi: image: mcoapi build: context: ./Mco.Api dockerfile: Dockerfile ports: - 56107:80 links: - mcodatabase depends_on: - "mcodatabase" - "mcoidentityserver" networks: - mconetwork volumes: postgresdata: networks: mconetwork: driver: bridge
docker-compose.override.yml
This is created by the Visual Studio plugin to inject extra values.
version: '2' services: mcoapi: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "80" mcoidentityserver: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "5000"
API Dockerfile
FROM microsoft/aspnetcore:1.1 ARG source WORKDIR /app EXPOSE 80 COPY ${source:-obj/Docker/publish} . ENTRYPOINT ["dotnet", "Mco.Api.dll"]
Identity Server Dockerfile
FROM microsoft/aspnetcore:1.1 ARG source WORKDIR /app COPY ${source:-obj/Docker/publish} . EXPOSE 5000 ENV ASPNETCORE_URLS http://*:5000 ENTRYPOINT ["dotnet", "Mco.IdentityServer.dll"]
API Startup.cs
Where we tell the API to use the Identity Server and set the Authority.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { // This can't work because we're running in docker and it doesn't understand what localhost:5000 is! Authority = "http://localhost:5000", RequireHttpsMetadata = false, ApiName = "api1" }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
Identity Server Startup.cs
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddIdentityServer() .AddTemporarySigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseIdentityServer(); app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } }
Identity Server Config.cs
public class Config { public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("api1", "My API") }; } public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; } }
Client
Running in a console app.
var discovery = DiscoveryClient.GetAsync("localhost:5000").Result; var tokenClient = new TokenClient(discovery.TokenEndpoint, "client", "secret"); var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result; if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return 1; } var client = new HttpClient(); client.SetBearerToken(tokenResponse.AccessToken); var response = client.GetAsync("http://localhost:56107/test").Result; if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine(JArray.Parse(content)); }
Thanks in advance.
IdentityServer4 support will last until the end of life of . NET Core 3.1 that means till November 2022. In that way, Duende provides new documentation for the fifth service version.
IdentityServer is an authentication server that implements OpenID Connect (OIDC) and OAuth 2.0 standards for ASP.NET Core. It's designed to provide a common way to authenticate requests to all of your applications, whether they're web, native, mobile, or API endpoints.
Ensure IssuerUri
is set to an explicit constant. We had similar issues with accessing Identity Server instance by the IP/hostname and resolved it this way:
services.AddIdentityServer(x => { x.IssuerUri = "my_auth"; })
P.S. Why don't you unify the authority URL to hostname:5000
? Yes, it is possible for Client and API both call the same URL hostname:5000
if:
hostname:5000
(check firewalls, network topology, etc.)DNS is the most tricky part. If you have any trouble with it I recommend you try reaching Identity Server by its exposed IP instead of resolving hostname
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With