'IdentityServer4 OpenIdConnect GetClaimsFromUserInfoEndpoint not setting additional claims

Mvc Hybrid application is not getting extra claims other than name, given_name and family_name (which I set them in access token) in id_token from ProfileService.

Below is the claims issued at the end of GetProfileDataAsync of ProfileService

Issued Claims from GetProfileDataAsync

And here is what i get in id_token:

Mvc Id_Token Claims

missing the picture claim i set on ProfileService.

So the main confusion is here:

Oidc Options

1. Isn't this mean to fetch UserInfo end point and merge them with id_token? If so, is this working as intended?

2. If this is working as intended and if I have to set the claims in GetProfileDataAsynch

    if (context.Caller == "ClaimsProviderIdentityToken") //(Or AccessToken)
    {
       //Identity Token claims
    } 

Why would I need to call UserInfo end point for profile scope? And if I have lots of scope requests wouldn't it exceed the maximum token size with lots of claims? Futhermore if I have to add all of them in id_token (or access token), what's the point of setting this property to true?

3. In case if i have many claims and when i wanted to get the UserInfo claims, do I need to call the UserInfo end point via acess token and merge them with identity token myself? Will it have exceeding the max token size problem? Or is it just a fool's errand?

Thanks for your time.



Solution 1:[1]

I also faced the same issue.. user claims are not mapped automatically.

To begin with my webapi bff(BackendForFrontEnd) configuration was something like below. And Identity server along with email claim emitted the claim "role".

.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.RequireHttpsMetadata = false;
            options.ClientId = _identityServerConfiguration.ClientId;
            options.ClientSecret = _identityServerConfiguration.ClientSecret;
            options.ResponseType = _identityServerConfiguration.ResponseType;
            options.UsePkce = _identityServerConfiguration.UsePkce;
            options.Authority = _identityServerConfiguration.AuthorityUrl;
            options.SaveTokens = true;
            var scopesRequested = _identityServerConfiguration.Scope;
            var scopes = scopesRequested.Split(",");
            foreach (var scope in scopes)
            {
                options.Scope.Add(scope);
            }

But after Authentication when i tried to access

HttpContext.User.FindFirst("role");
HttpContext.User.FindFirst("email");

I got null for both values Then I added the below setting in the AddOpenIdConnect method specified above.

options.GetClaimsFromUserInfoEndpoint = true;

After which

HttpContext.User.FindFirst("role"); --> It still gave null
HttpContext.User.FindFirst("email"); --> It worked.

Then I added below code in the AddOpenIdConnect method

 options.ClaimActions.MapUniqueJsonKey("role", "role");

After which

 HttpContext.User.FindFirst("role"); --> It Worked
 HttpContext.User.FindFirst("email"); --> It worked.

My final config was like:

 .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
            {
                options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.ClaimActions.MapUniqueJsonKey("role", "role");
                options.ClaimActions.MapUniqueJsonKey("grp", "Group");
                options.RequireHttpsMetadata = false;
                options.ClientId = _identityServerConfiguration.ClientId;
                options.ClientSecret = _identityServerConfiguration.ClientSecret;
                options.ResponseType = _identityServerConfiguration.ResponseType;
                options.UsePkce = _identityServerConfiguration.UsePkce;
                options.Authority = _identityServerConfiguration.AuthorityUrl;
                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;
                var scopesRequested = _identityServerConfiguration.Scope;
                var scopes = scopesRequested.Split(",");
                foreach (var scope in scopes)
                {
                    options.Scope.Add(scope);
                }

Explaination: Initially id_token from cookie was used to build UserPrincipal

Then setting GetClaimsFromUserInfoEndpoint to true made the UserPrincipal to use claims from access_token as well.

But it just worked for the name and email type of cliams. Finally it was MapJsonKey which actually worked for the remainder of the claims

This article has an excellent explanation for this. https://damienbod.com/2019/11/01/user-claims-in-asp-net-core-using-openid-connect-authentication/comment-page-1/?unapproved=139595&moderation-hash=e41d293e5b41b039a65a776a187c9af7#comment-139595

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GPuri