Admittedly, this is a first stab at building an Asp.Net Core web api project.. One requirement is to support OAuth2. The Api and Identity server are two separate projects, both started from an Asp.Net core Empty template.
Identity server is up and running, and tokens are being provided via the resource owner flow. Getting the token is fine, scopes and relevant access_token details appear to be correct.
When I issue a get request to my resource end-point, I get the following at first...
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:12886/v1/mystuff
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[2]
Successfully validated the token.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[3]
HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[8]
AuthenticationScheme: Bearer was successfully authenticated.
info: IdentityModel.AspNetCore.ScopeValidation.ScopeValidationMiddleware[0]
Scopes found on current principal: scope: stuffdetails, scope: stuffmover
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[8]
AuthenticationScheme: Bearer was successfully authenticated.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
Authorization was successful for user: 939d72dd-654c-447f-a65d-d0426b1eca59.
So, I can tell middleware is validating my token, reading scopes, and the authenticating the token. However, immediately following the initial success, I get authorization failures.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed for user: 939d72dd-654c-447f-a65d-d0426b1eca59.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[13]
AuthenticationScheme: Bearer was forbidden.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action TestApi.StuffController.GetStuff (TestApi) in 32.4439ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 1207.1769ms 403
Here is what I believe are the relevant bits in startup.
ConfigureServices...
services.AddMvcCore()
.AddAuthorization(opts =>
{
opts.AddPolicy("stuffdetails",
policy => policy.RequireClaim("stuffdetails"));
}
)
.AddJsonFormatters();
services.AddOptions();
Configure -- Note that I know my configOptions are correct because the initial token challenge is successful.
var authServerOptions = new IdentityServerAuthenticationOptions
{
Authority = configOptions.Value.AuthServerSettings.AuthServerURI,
RequireHttpsMetadata = configOptions.Value.AuthServerSettings.RequiresHttpsMetaData,
ApiName = configOptions.Value.AuthServerSettings.ApiName,
AllowedScopes = configOptions.Value.AuthServerSettings.AllowedScopes,
SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt,
AuthenticationScheme = "Bearer",
SaveToken = true,
ValidateScope = true
};
app.UseIdentityServerAuthentication(authServerOptions);
app.UseMvc();
Stuff Controller
[Route("v1/[controller]")]
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
public class StuffController : Controller
{
[HttpGet]
[Authorize(Policy = "stuffdetails")]
public JsonResult GetStuff()
{
return new JsonResult(new
{
Message = "You've got stuff.."
});
}
}
If I remove the Authorize attribute from the GetStuff method, everything is fine because as the log showed, the bearer token is authorized.
The questions:
Any help is greatly appreciated..
Is authorization failing because my policy is incorrect, and if so how should it be setup?
What you've got looks correct, but you can easily verify by just removing the 'policy' part of your Authorize attribute: if it now works then the problem is to do with your policy, if it still fails then it is a broader problem than just your policy. I'm assuming you're adding the 'stuffdetails' claim into your access_token with your own implementation of the IProfileService
?
If I want to validate a token contains the proper claims, and was authorized, is it correct to use policies as I have?
Yes that seems to be the aspnet core way of doing custom authorization.
Am I making a mistake trying to use UseIdentityServerAuthentication instead of UseJwtBearerAuthentication?
I am using the UseIdentityServerAuthentication
with the ResourceOwnerPassword
flow. I'd be interested to hear if the UseJwtBearerAuthentication
approach is preferred or offers other features.
The error on my part was the way I created my policy:
opts.AddPolicy("stuffdetails",
policy => policy.RequireClaim("stuffdetails"));
Should be:
opts.AddPolicy("stuffdetails",
policy => policy.RequireClaim("scope","stuffdetails"));
The policy was supposed to confirm the scopes included "stuffdetails".. A great resource for anyone having trouble is a post by damienbod, Authorization Policies and Data Protection with IdentityServer4 in ASP.Net Cord
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