I have run into a very strange problem, and I am guessing that I am missing something in my setup.
I have an WebAPI that is secured by an IdentityServer4. It's only using Client_credentials. If i write the wrong ClientId och ClientSecret that user is not Authenticated, and I can't connect to my WebAPI. But if I write the wrong scope name the request is still processed and I get my response back, the strange part is that an exception is thrown, but for some reason it's ignored by the .NET Core Framework.
Here are some debug info from my output window.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET https://localhost:44360/v1/bookings
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Bearer was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'.
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executing endpoint 'TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api)'
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Get", controller = "Bookings"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[System.Collections.Generic.IEnumerable`1[System.String]]] Get() on controller TRS.BookingService.Api.Controllers.BookingsController (TRS.BookingService.Api).
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api) - Validation state: Valid
TRS.BookingService.Api.Controllers.BookingsController:Information: Getting all bookings
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 96.2159ms.
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor:Information: Executing ObjectResult, writing value of type 'System.String[]'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api) in 280.2344ms
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executed endpoint 'TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api)'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 1345.3829ms 200 application/json; charset=utf-8
So even that there is an exception thrown that says that the token isn't validated the request is still allowed to continue and execute and the response is sent back to the client.
This is how the ConfigureServices looks like:
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:44392/";
options.Audience = "FAKE_SCOPE";
});
And the Configure() Methods
app.UseAuthentication();
app.UseMvc();
This is how the JWT Token looks like:
{
"nbf": 1562062882,
"exp": 1562066482,
"iss": "https://localhost:44392",
"aud": [
"https://localhost:44392/resources",
"bookingApi"
],
"client_id": "clientId",
"scope": [
"bookingApi"
]
}
And this is the Client code calling the API.
var idpUrl = "https://localhost:44392/";
var clientId = "clientId";
var clientSecret = "secret";
var scope = "bookingApi";
var accessToken = await GetAccessTokenAsync(new Uri(idpUrl), clientId, clientSecret, scope);
string content = await GetContent(new Uri("https://localhost:44360/v1/bookings"), accessToken);
I guess I have missed something when it comes to Authorization, I have tried different
services.Authorization()
In the ConfigureServices() methods but it doesn't help, guess I have written it wrong.
Best Regards Magnus
I came across this article after hitting the same issue. After much banging of head I discovered that it was caused in my case by using services.AddMvcCore() (with .AddJsonFormatters().AddDataAnnotations() in my case) rather than services.AddMvc(). Only with .AddMvcCore() do I get a 401 for token validation failure.
Seems that you need to add .AddAuthorization() to the mix when using .AddMvcCore as it is not added by default. Without it, the token validation fails, but the request pipeline continues quite happily.