Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding claims to IdentityServer setup by AddIdentityServer

I have a SPA that has an ASP.NET Core web API together with the inbuilt identity server switched on using AddIdentityServer and then AddIdentityServerJwt:

services.AddIdentityServer()
   .AddApiAuthorization<User, UserDataContext>();
services.AddAuthentication()
   .AddIdentityServerJwt();

I also have an authorization policy setup that requires an "Admin" role claim:

services.AddAuthorization(options =>
{
    options.AddPolicy("IsAdmin", policy => policy.RequireClaim(ClaimTypes.Role, "Admin")); 
});

I have a controller action that uses this policy

[Authorize(Policy = "IsAdmin")]
[HttpDelete("{id}")]
public IActionResult Deleten(int id)
{
    ...
}

The authenticated user does have the "Admin" role claim:

enter image description here

The access token for this authentication user doesn't appear to contain the admin claim:

enter image description here

I get a 403 back when trying to request this resource with the admin user:

enter image description here

So, if I'm understanding this correctly, IdentityServer isn't including the admin role claim and so the user isn't authorized to access the resource.

Is it possible to configure the claims that IdentityServer uses using AddIdentityServerJwt? or am I misunderstanding why this is not working.

like image 963
Carl Rippon Avatar asked May 23 '19 20:05

Carl Rippon


People also ask

What is Identity Server claim?

IdentityServer emits claims about users and clients into tokens. You are in full control of which claims you want to emit, in which situations you want to emit those claims, and where to retrieve those claims from.

Is IdentityServer paid?

IdentityServer is a free and open-source framework that has been used by thousands of companies to develop their single sign-on solutions. For the last four years, Rock Solid Knowledge has been working with the creators of IdentityServer to provide a commercial ecosystem around the framework.


2 Answers

One of the other answers is really close to the specific use case in question but misses the point about it being SPA.

Firstly you must add your IProfileService implementation like suggested already:

public class MyProfileService : IProfileService
{
    public MyProfileService()
    { }

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        //get role claims from ClaimsPrincipal 
        var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);

        //add your role claims 
        context.IssuedClaims.AddRange(roleClaims);
        return Task.CompletedTask;
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        // await base.IsActiveAsync(context);
        return Task.CompletedTask;
    }
}

But then go ahead and do this:

services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
                .AddProfileService<MyProfileService>();

And your claim will be exposed on the JWT. Replace the ClaimTypes.Role constant with any string corresponding to the claim type you want to expose.

like image 57
JKJ Avatar answered Oct 03 '22 23:10

JKJ


On Identity Server side , you can create Profile Service to make IDS4 include role claim when issuing tokens .

You can get role claims from ClaimsPrincipal or get the roles from database and create profile service like :

public class MyProfileService : IProfileService
{
    public MyProfileService()
    { }

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        //get role claims from ClaimsPrincipal 
        var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);

        //add your role claims 
        context.IssuedClaims.AddRange(roleClaims);
        return Task.CompletedTask;
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        // await base.IsActiveAsync(context);
        return Task.CompletedTask;
    }
}

And register in Startup.cs:

services.AddTransient<IProfileService, MyProfileService>();

On client side , you should map the role claim from your JWT Token and try below config in AddOpenIdConnect middleware :

  options.ClaimActions.MapJsonKey("role", "role", "role");
  options.TokenValidationParameters.RoleClaimType = "role";

Then your api could validate the access token and authorize with role policy .

like image 31
Nan Yu Avatar answered Oct 03 '22 23:10

Nan Yu