Zeus82
Zeus82

Reputation: 6375

ASP Core Add Custom Claim to Auth Token

I'm using openiddict and ASP Identity, and I am trying add a "GroupId" as a claim to the auth token that is returned when logging in (using the /connect/token endpoint - see example I followed below). The GroupId is a property in my AplicationUser class.

I have tried using an IClaimsTransformer but that seems clunky, I can't easily get to the UserManager from the ClaimsTransformationContext.

How would I go about either getting the UserManager through DI in my IClaimsTransformer or just adding the GroupId to the token that is generated at the connect/token endpoint?

I followed this example for setting up my site. This is what I would like to do:

var groupGuid = User.Claims.FirstOrDefault(c => c.Type == "GroupGuid");

Upvotes: 3

Views: 4323

Answers (2)

Mikhail Smal
Mikhail Smal

Reputation: 176

There is a couple of ways to achieve it:
First, override CreateUserPrincipalAsync method in your custom SignInManager:

public override async Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationAdmin user)
{
    var principal = await base.CreateUserPrincipalAsync(user);
    // use this.UserManager if needed
    var identity = (ClaimsIdentity)principal.Identity;
    identity.AddClaim(new Claim("MyClaimType", "MyClaimValue"));            

    return principal;
}

The second way is to override CreateAsync method of your custom UserClaimsPrincipalFactory:

public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
    var principal = await base.CreateAsync(user);

    var identity = (ClaimsIdentity)principal.Identity;
    identity.AddClaim(new Claim("MyClaimType", "MyClaimValue"));

    return principal;
}

which is, basically, the same, because base.CreateUserPrincipalAsync method in SignInManager calls this.UserClaimsPrincipalFactory() inside.

Don't forget to add your custom implementations into services:
either

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSignInManager<CustomSignInManager>();
}

or

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomClaimsPrincipalFactory>();
}

Upvotes: 7

adem caglin
adem caglin

Reputation: 24063

ASP Core Add Custom Claim to Auth Token

You can't change a token after it is signed by IdP, so you can't add claim to token.

I have tried using an IClaimsTransformer but that seems clunky, I can't easily get to the UserManager from the ClaimsTransformationContext.

I guess your problem is related this github issue. In summary(as far as i understand) if ClaimsTransformer class is registered as singletion and one of the its dependency is scoped or transient, it causes captive dependency. In this case you should use Service Locator pattern to avoid from captive dependency. Your code may be something like this(from @PinpointTownes' comment):

public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context) 
{
    var userManager= context.Context.RequestServices.GetRequiredService<UserManager>();
    //
} 

-- My thoughts about your case --

You have basically two options to achieve your goal:

Add claim to token when token is generated by IdP:

You don't need this method most cases, but if you want to use it:

  • You should have control over IdP, because this option is possible on the IdP(as far as i understand your IdP and Resource Server is same, so you have control over IdP, but it might not be possible always) .
  • You should take care of inconsistency when using this option, because the claim is stored in the token and doesn't get each request. So the real value of claim might be different from claim in the token.(I don't prefer it for roles, permissions, groups etc. because these claims can be change anytime).

p.s: i don't know if it is possible to add claims to token with Openiddict.

Claims Transformation

Actually i used HttpContext.Items to store additional claims before i discovered this method and it worked well for me. But i think better way is to use Claims Transformation and it fits into your case.

Upvotes: 1

Related Questions