Alexu
Alexu

Reputation: 1195

How to access identity provider (idp) claim from .net Core web API in IdentityServer4?

In my .Net Core web API protected by IdentityServer4, I need to decide what identity provider (Google, Windows, or local, for instance) authenticated the user. So far, I am not sure how to do that.

If I search for idp claim from access_token in a controller, as shown below, I can see the claim value correctly

var accessToken = await HttpContext.GetTokenAsync("access_token");
var token = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
var claim = token.Claims.First(c => c.Type == "idp").Value;

But if I try to find it using AuthorizationHandlerContext in a non-controller class in API as following, as shown in code below, it is not there

    var identity = context.User.Identity as ClaimsIdentity;
    if (identity != null)
    {
        IEnumerable<Claim> claims = identity.Claims;
        // var v = identity.FindFirst("idp").Value;
    }

So looks like that idp is indeed in the token, it just not accessible from the non-controller class where it is needed. How do I get idp from non-controller class in API?

UPDATE - 1

Here is my ConfigureService in my API

public void ConfigureServices(IServiceCollection services)
{
    IdentityModelEventSource.ShowPII = true; // test only
    services.AddControllers();

    services.AddControllers()
         .AddNewtonsoftJson(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );          
    });

    services.Configure<QLHostOptions>(Configuration.GetSection(QLHostOptions.Host));

    services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options =>
    {
        options.Authority = Configuration.GetSection(QLHostOptions.Host).Get<QLHostOptions>().IdentityGateway;
        options.SaveToken = true; 

        // test only
        options.RequireHttpsMetadata = false;

        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    }).AddOpenIdConnect(options =>
    {
        options.ClaimActions.Remove("aud");
    });

    services.AddTransient<IAuthorizationPolicyProvider, QLPolicyProvider>();
    services.AddTransient<IAuthorizationHandler, QLPermissionHandler>();

    services.AddTransient<gRPCServiceHelper>();

}

UPDATE-2

Changed ...Remove("idp") to inside AddJwtBearer, as Tory suggested, but it doesn't take it (see screenshot below):

enter image description here

and here is the access token from API

"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBFM0Y2MkRGMTdFQUExQURFRTc1NDQzQzQ0M0YxRkU2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NDAwMzExMDcsImV4cCI6MTY0MDAzNDcwNywiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NjAwNSIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjYwMDUvcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoibXZjIiwic3ViIjoiZGM0YWI1OGMtNGVjMC00ZTAyLWIxM2YtYzEyYzk1MzJlNzcyIiwiYXV0aF90aW1lIjoxNjQwMDMxMTA2LCJpZHAiOiJHb29nbGUiLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6IjJEQ0hXNVRER1E3NDNSUEpOWE43SVJIWlRIVllIUTRJIiwibmFtZSI6IkxpZmVuZyBYdSIsImVtYWlsIjoibGlmZW5neHUyNkBnbWFpbC5jb20iLCJyb2xlIjoiUUxBZG1pbiIsInByZWZlcnJlZF91c2VybmFtZSI6IjM1ZGJkMmY2LTlmNDUtNDJhYy04M2EzLTgzZmUyMTFjNTNiNSIsIklzRW5hYmxlZCI6IlRydWUiLCJRaWNMaW5rVUlEIjoiIiwianRpIjoiQzE3Qjc2QzQ0NjA4MzkxMDBENEExMEM4Q0YwQzA1NDEiLCJzaWQiOiIzMEY5NTA5NzQ3OUUxMzAyMUVBQTdDOTAzNzg4MDcxNiIsImlhdCI6MTY0MDAzMTEwNywic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsImVtYWlsIiwiUWljTGlua0NJRCIsIlFpY0xpbmtVSUQiLCJyb2xlcyIsIklzRW5hYmxlZCIsIkxpZmVuZ0FQSSIsIlFpY0xpbmtBUEkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhbXIiOlsiZXh0ZXJuYWwiXX0.boZCqYImWfkE48X5UgFOAAz9bR6CH2cwAYHGd4Ykg0vDH9qnYdje5Zmqov4HpINsu_rt16zxAX_JCEn0hvdznXK2NQyZSBGsjF0tcMgtOY0__kAfhpOT-fORakiIjeMWIKG7tPEHCxSib0wNuMNw6i3o1giAnPt0ch2DH0fBtaEYkq4MRKMCteFuqbX0cogXIuMewNywMvrHv4_MixhMy3L8_xIwFvTZ67jhUn4Fd5X58-jc-RPNudcP95XIjzHm9OzWfgegV1IAKjsv98XEYX1pUxm-nrOMgYWxEJSyxEpp0L_9RzKTr_LZ-ep-x5QRvVewgiozJV3mse0pHgTjbw"

Upvotes: 0

Views: 580

Answers (1)

Tore Nestenius
Tore Nestenius

Reputation: 19901

By default many of the more internal claims in a token are removed from the User ClaimsPrinicpal claims.

If you want to get a specific claim into your user, you can use in the client:

}).AddOpenIDConnect(options =>
{
    //Will result in that the aud claim is not removed.
    options.ClaimActions.Remove("idp");
...

secondly, some of the claims are renamed and if you want to disable that renaming, you can add:

// By default, Microsoft has some legacy claim mapping that converts
// standard JWT claims into proprietary ones. This removes those mappings.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

For the API you should not need to do anything special to get the idp claim. I just ran a test with this setup in .NET 5:

public void ConfigureServices(IServiceCollection services)
{

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMyJwtBearer(opt =>
    {
        opt.IncludeErrorDetails = true;
        opt.MapInboundClaims = false;
        opt.TokenValidationParameters.RoleClaimType = "role";
        opt.TokenValidationParameters.NameClaimType = "name";
        opt.Audience = "paymentapi";
        opt.Authority = "https://localhost:6001";
    });

    services.AddControllers();
}

I did give it a test on .NET 5 and if I have this access token:

{
  "nbf": 1640033816,
  "exp": 1640037416,
  "iss": "https://localhost:6001",
  "aud": "paymentapi",
  "client_id": "clientcredentialclient",
  "managment": "yes",
  "email": "[email protected]",
  "name": "tore nestenius",
  "idp": "Google",
  "role": [
    "admin",
    "developer",
    "support"
  ],
  "website": "https://www.tn-data.se",
  "jti": "5DC46A29372031F0AA6F7B62B5FDCCD6",
  "iat": 1640033816,
  "scope": [
    "payment"
  ]
}

Then my user in my API controller contains the idp claim:

enter image description here

To complement this answer, I wrote a blog post that goes into more detail about this topic: Debugging OpenID Connect claim problems in ASP.NET Core

Upvotes: 1

Related Questions