Skip to content

Beware in ASP.NET Core 2.0: Claims transformation might run multiple times

August 30, 2017

In ASP.NET Core, you can add a claims transformation service to your application, as such:

public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc();
   services.AddAuthentication(options=>
   {
      options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
   }).AddCookie();

   services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
}

And then your ClaimsTransformer might look like this:

class ClaimsTransformer : IClaimsTransformation
{
   public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
   {
     ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("now", DateTime.Now.ToString()));
     return Task.FromResult(principal);
   }
}

And that might be fine. But beware that this might be invoked multiple times. If an app has this code (perhaps in different locations in the app which might be likely):

await HttpContext.AuthenticateAsync();
await HttpContext.AuthenticateAsync();

Then each time AuthenticateAsync is called the claims transformer is invoked. So given the above implementation we’d be adding the “now” claim multiple times.

Moral of the story, claims transformation should be more defensive and/or return a new principal, as such:

class ClaimsTransformer : IClaimsTransformation
{
   public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
   {
      var id = ((ClaimsIdentity)principal.Identity);

      var ci = new ClaimsIdentity(id.Claims, id.AuthenticationType, id.NameClaimType, id.RoleClaimType);
      ci.AddClaim(new Claim("now", DateTime.Now.ToString()));

      var cp = new ClaimsPrincipal(ci);

      return Task.FromResult(cp);
   }
}

HTH

 

9 Comments leave one →
  1. September 12, 2017 12:20 pm

    Are you sure this is .net core 2.0 code?

    services.AddAuthentication(options=>
    {
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    }).AddCookie();

    It doesn’t work. What works is :
    services.AddAuthentication(options =>
    {
    options.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
    });

    And I cant seem to find where AddCookie() is and what it’s use is.

  2. Manu permalink
    November 2, 2017 10:03 pm

    how can we invoke TransformAsync in startup class

    • December 5, 2017 5:12 pm

      IIRC, they changed it so you must inject it as a service now in 2.0.

  3. November 3, 2017 7:38 pm

    How to use it in windows authentication scenario

  4. July 20, 2018 12:57 pm

    It still adds the new claim multiple times in .net core 2.1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: