1

I have followed the duende tutorials up until 5 (adding the identity framework). I have completed the tutorial (i.e. I have a razor client, a c# api, and an identity server application).

I then went ahead and removed the favorite color, and added other fields such as nickname, city, country (amongst others).

I made the necessary modifications to the identity server (namely updated the mapping service to map user data to claims, and one IdentityResource to represent all my custom claims (nickname, country, city etc).

IdentityServer Configured as follows:

IEnumerable<IdentityResource> IdentityResources =
    new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResource("myApi.Data", new [] {   nameof(User.NickName),
                                                            nameof(User.Country),
                                                            nameof(User.City)})};

IEnumerable<ApiScope> ApiScopes =
    new List<ApiScope>
    {
            new ApiScope("api1", "My API"),
            new ApiScope(IdentityServerConstants.LocalApi.ScopeName)
    };

IEnumerable<Client> Clients =
new List<Client>
{
        // interactive ASP.NET Core Web App
        new Client
        {
            ClientId = "web",
            ClientSecrets = { new Secret("secret".Sha256()) },

            AllowedGrantTypes = GrantTypes.Code,
                
            // where to redirect to after login
            RedirectUris = { "https://localhost:7070/signin-oidc" },

            // where to redirect to after logout
            PostLogoutRedirectUris = { "https://localhost:7070/signout-callback-oidc" },

            AllowOfflineAccess = true,

            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                "api1",
                "myApi.Data",
                IdentityServerConstants.LocalApi.ScopeName
            }
        }
};


builder.Services
    .AddIdentityServer(options =>
{
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;

    // see https://docs.duendesoftware.com/identityserver/v6/fundamentals/resources/
    options.EmitStaticAudienceClaim = true;
})
.AddInMemoryIdentityResources(IdentityResources)
.AddInMemoryApiScopes(ApiScopes)
.AddInMemoryClients(Clients)
.AddAspNetIdentity<User>()
.AddProfileService<CustomProfileService>();

The Razor Client uses the following piece of code to authenticate vs idsvr (using addOpenIdConnect):

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
    options.Authority = "https://localhost:44302";

    options.ClientId = "web";
    options.ClientSecret = "secret";
    options.ResponseType = "code";

    options.SaveTokens = true;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("offline_access");
    options.Scope.Add("api1");
    options.Scope.Add("myApi.Data");
    options.Scope.Add("IdentityServerApi");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.ClaimActions.MapAll();
});

MyApi is connected to the identity server as follows:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://localhost:44302";
        options.TokenValidationParameters.ValidateAudience = false;
        options.MapInboundClaims = true;
    });

I have noticed that the razor client is able to see my custom claims when looping through User.Claims: enter image description here

enter image description here

However my api is also accessing User.Claims but sees much less data! enter image description here enter image description here

The client is sending the request to the api by passing the accessToken as a bearer:

enter image description here

Why is this so?


Update following tips:

I have followed the debugging for my client, and can see my fields from the get user information endpoint, but not from the id token: enter image description here

As for my api, I added the logic for on token validated and can see the claims, but not my custom claims: enter image description here

Since the client is using cookies, but the api is working through a JWTBearer, could it be that my access token does not have this user information? Makes sense because the access token should not have personal information but rather the users access, and I have defined my claims as Identity resource. How would I go about it if I would require the access the user information claims by the api which is working through JWTBearer and not OpenIdconnect/Cookies?


Update 2: I have changed my idsvr config to have my custom claims as an api Scope, and now I can see my custom claims in my access token from the web api, however now the UI cannot see these claims!.

Style
  • 67
  • 9

1 Answers1

1

You control what claims should go into the ID token and what claims should go into the access token using the three core resource types in IdentityServer (IdentityResource, ApiResource, and ApiScope). So that's why you see different claims in each token. Which claims to include all depends on your use-case and needs.

enter image description here

If you want to learn about the specifics, then I have written a set of blog post about debugging claim problems here:

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
  • Thanks for helping out Tore ! I have updated my post above to reflect my findings so far. Since the client is using cookies, but the api is working through a JWTBearer, could it be that my access token does not have this user information? Makes sense because the access token should not have personal information but rather the users access, and I have defined my claims as Identity resource. How would I go about it if I would require the access the user information claims by the api which is working through JWTBearer and not OpenIdconnect/Cookies? – Style Jun 20 '23 at 10:03
  • Adding user claims to the access token is fine, but only what the API needs to use to function or to authorize the action in the API. So, often the claims in the ID and access token are different. Authorization is a separate function that you need to implement after the JwtBearer has accepted the access token. – Tore Nestenius Jun 20 '23 at 10:19
  • You define in the ApiScope/ApiResources in IdentityServer which user claims should be added to the access token. Feel free to accept my answer if it solved your problem. – Tore Nestenius Jun 20 '23 at 10:20
  • Ok so you're saying that I should swap my config from being an identity resource to being an apiScope/resource - this way the information should be in the access token. Is that correct? Also What if I wanted the user information to be separate from the access Token? Is there a way to pass the id token? As far as I'm aware, I cannot use cookies since i have three seperate projects (client, api, idsvr). And when my client authenticates vs idsvr, the cookie cannot be sent to the api. – Style Jun 20 '23 at 10:28
  • 1
    You can still keep the user claims that you want to get into the user cookie (IdentityResources). Next ,you also need to consider the size of the session cookie and tokens. So, just include the claims you need for the user session and the access token. – Tore Nestenius Jun 20 '23 at 11:52