Reputation: 1261
Have an API written in .NET 8
My pipeline goes something like
app.UseAuthentication()
....
app.UsePreAuthMiddleWares() // Have a group of middlewares required prior to authorization
app.UseAuthorization()
app.UsePostAuthMiddleWares() // Have a group of middlewares required post authorization
There are two tokens supported. I was initially adding a default policy like:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
// Specify Options and Events
});
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
And then use it like:
[ApiController]
[Authorize]
public class BaseApiController : ControllerBase
{
}
Here, I was to get context.User.Identity.IsAuthenticated as true and would also get the user claims. For authenticating the other token would drop the [Authorize] attribute for those controllers and add an IAsyncAuthorizationFilter and validate the other token there. I would not IsAuthenticated as true here as expected nor the claims but the required middleware was skipped for these APIs.
For simplicity and for handling all auth errors at one point - via the JwtBearerEvents I changed it to add two policies for both the tokens like:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("Policy1", options =>
{
// Specify Options and Events
})
.AddJwtBearer("Policy2", options =>
{
// Specify Options and Events
});
services.AddAuthorization(options =>
{
options.AddPolicy("Policy1", new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build());
options.AddPolicy("Policy2", new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build());
});
And using it like:
[ApiController]
[Authorize(Policy = "Policy1")]
public class BaseApiController : ControllerBase
{
}
After these changes I have stop getting IsAuthenticated as false in the pre-authorization middlewares and the claims are empty. Need these prior as I have an IAuthorizationPolicyProvider added and based on the user claims I am fetching and adding some permission claims that cause the policy provider to succeed.
Am I missing something here and is there a way to get the user claims to work with this code potentially for both policies?
Edit: Have tried creating two policies with the authentication scheme specified in AddJwtBearer as well as setting a single default policy with two auth schemes, but it gave similar results.
I am trying to have two JWT tokens supported in my service where both have access to different actions - no overlap.
Upvotes: 0
Views: 44
Reputation: 1261
The policy scheme is what eventually worked for me - https://learn.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-8.0
Added a default policy scheme
services.AddAuthentication(options => {
options.DefaultScheme = "MultiPolicy";
options.DefaultChallengeScheme = "MultiPolicy";
})
.AddJwtBearer("Policy1", options => {
// Specify Options and Events
})
.AddJwtBearer("Policy2", options => {
// Specify Options and Events
})
.AddPolicyScheme("MultiPolicy", options => {
options.ForwardDefaultSelector = context => {
// Forward to required policy based on token claims
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Policy1", new AuthorizationPolicyBuilder("Policy1")
.RequireAuthenticatedUser()
.Build());
options.AddPolicy("Policy2", new AuthorizationPolicyBuilder("Policy1")
.RequireAuthenticatedUser()
.Build());
});
Then I could call it as
[Authorize(Policy = "Policy1")]
Doing so I would get Authenticated as true in any middlewares registered to run between UseAuthentication() and UseAuthorization()
Upvotes: 0
Reputation: 19901
This part looks a bit wrong. Policy1 and Policy2 below are the names of the handlers and the part in JwtBearerDefaults.AuthenticationScheme should point out which hander should check for the token and create the identity.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("Policy1", options =>
{
// Specify Options and Events
})
.AddJwtBearer("Policy2", options =>
{
// Specify Options and Events
});
A more correct solution would be for example to do:
services.AddAuthentication("Policy1");
The above says, that Use the handler named Policy for all authentication operations. It is a bit tricker if you want to support multiple handlers.
Upvotes: 0