I'm in the process of migrating from .NET Core 1.1 to 2.0 and while updating the IdentityServer4 configuration, I got stuck with the following situation.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var corsOrigins = configs.SelectMany(c => c.AllowedCorsOrigins).ToList();
var cors = new DefaultCorsPolicyService(_loggerFactory.CreateLogger<DefaultCorsPolicyService>())
{
AllowedOrigins = corsOrigins
};
services.AddSingleton<ICorsPolicyService>(cors);
services.AddIdentityServer()
.AddSigningCredential(cert)
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.ApiName = "api1";
options.Authority = Configuration.GetValue<string>("Authority");
options.ClaimsIssuer = Configuration.GetValue<string>("Authority");
options.RequireHttpsMetadata = Environment.IsProduction();
options.SupportedTokens = SupportedTokens.Both;
});
services.AddMvc();
// ...
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IClientService clientService)
{
app.UseIdentityServer();
app.UseMvcWithDefaultRoute();
}
The login and call to my ProfileService works fine, but when I'm sending a request to the protected API, my ClaimsPrincipal (accessed via HttpContext.User) is not authenticated, and his claims are empty.
info: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
ValidatedAuthorizeRequest
{
"ClientId": "app",
"RedirectUri": "http://localhost:3000/callback",
"AllowedRedirectUris": [
"http://localhost:3000/callback",
"http://localhost:3000/silent_renew.html",
"http://192.168.0.44:3000/callback",
"http://192.168.0.44:3000/silent_renew.html"
],
"SubjectId": "1#3",
"ResponseType": "token",
"ResponseMode": "fragment",
"GrantType": "implicit",
"RequestedScopes": "api1",
"State": "0bedf473c2fd48d8859655eaf3b6affe",
"SessionId": "b9376a8bf95b08631ffdc169ef76b745",
"Raw": {
"client_id": "app",
"redirect_uri": "http://localhost:3000/callback",
"response_type": "token",
"scope": "api1",
"state": "0bedf473c2fd48d8859655eaf3b6affe"
}
}
dbug: IdentityServer4.Services.DefaultConsentService[0]
Client is configured to not require consent, no consent is required
dbug: IdentityServer4.ResponseHandling.AuthorizeResponseGenerator[0]
Creating Implicit Flow response.
dbug: IdentityServer4.Services.DefaultClaimsService[0]
Getting claims for access token for client: app
dbug: IdentityServer4.Services.DefaultClaimsService[0]
Getting claims for access token for subject: 1#3
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 OPTIONS http://localhost:5000/api/data
dbug: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[1]
The request is a preflight request.
dbug: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[2]
The request has an origin header: 'http://localhost:3000'.
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
Policy execution successful.
dbug: Microsoft.AspNetCore.Server.Kestrel[9]
Connection id "0HLCDV66PUEO9" completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 21.7776ms 204
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/api/data application/json
dbug: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[2]
The request has an origin header: 'http://localhost:3000'.
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
Policy execution successful.
dbug: IdentityServer4.Hosting.CorsPolicyProvider[0]
CORS request made for path: /api/data from origin: http://localhost:3000 but was ignored because path was not for an allowed IdentityServer CORS endpoint
dbug: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[9]
AuthenticationScheme: idsrv was not authenticated.
dbug: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[9]
AuthenticationScheme: idsrv was not authenticated.
Any help would be greatly appreciated. Thanks!
Does the API controller/action have [Authorize(Scheme="Bearer")]?
The controller does have the [Authorize] attribute, and after changing it to [Authorize("Bearer")] or [Authorize(AuthenticationSchemes = "Bearer")] nothing changed.
I'm wondering about the debug line CORS request made for path: /api/data from origin: http://localhost:3000 but was ignored because path was not for an allowed IdentityServer CORS endpoint. Maybe I'm missing something in the CORS config?
Configure app.UseCors(builder =>
{
// Allowed CORS origins only for trusted clients
var corsOrigins = new List<string>();
foreach (var client in clientService.GetClients())
{
foreach (var corsOrigin in client.AllowedCorsOrigins)
{
corsOrigins.Add(corsOrigin);
}
}
var origins = new string[corsOrigins.Count];
corsOrigins.CopyTo(origins, 0);
builder.WithOrigins(origins); // contains all of the trusted origins
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
// ...
app.UseIdentityServer(); ...
When I change services.AddAuthentication() to services.AddAuthentication("Bearer"), the problem gets reversed. Now an already existing token is accepted by the API, but the login fails at the call to await HttpContext.SignInAsync() with an exception::
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method API.Quickstart.Account.AccountController.Login (API) with arguments (API.Quickstart.Account.LoginInputModel, login) - ModelState is Valid
dbug: IdentityServer4.Hosting.IdentityServerAuthenticationService[0]
Augmenting SignInContext
dbug: IdentityServer4.Hosting.IdentityServerAuthenticationService[0]
Adding idp claim with value: local
dbug: IdentityServer4.Hosting.IdentityServerAuthenticationService[0]
Adding amr claim with value: pwd
dbug: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[9]
AuthenticationScheme: Bearer was not authenticated.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action API.Quickstart.Account.AccountController.Login (API) in 3552.4471ms
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLCEEULOM4AO", Request id "0HLCEEULOM4AO:00000003": An unhandled exception was thrown by the application.
System.InvalidOperationException: No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Bearer
at Microsoft.AspNetCore.Authentication.AuthenticationService.<SignInAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Hosting.IdentityServerAuthenticationService.<SignInAsync>d__7.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\IdentityServerAuthenticationService.cs:line 72
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.<SignInAsync>d__11.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Extensions\HttpContextAuthenticationExtensions.cs:line 278
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.<SignInAsync>d__3.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Extensions\HttpContextAuthenticationExtensions.cs:line 104
We showed hosting an API in IS4 in our NDC talk from January in London. https://vimeo.com/254635632
Got it!
The problem was I was trying to access HttpContext.User from a custom middleware before the call to the controller. There, the user was null. I had to call await httpContext.AuthenticateAsync("Bearer") to get the user data.
Very informative talk - thanks for your help!
I'm also facing same issue. Below is how I configuration..
// removed
services.AddIdentityServer();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignOutScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultForbidScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme,
options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
}, null);)
This is closed. I was doing same mistake.
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.
Most helpful comment
Got it!
The problem was I was trying to access
HttpContext.Userfrom a custom middleware before the call to the controller. There, the user was null. I had to callawait httpContext.AuthenticateAsync("Bearer")to get the user data.Very informative talk - thanks for your help!