0

Im trying to attach some user data for display purposes to my identity token in duende identityserver but only succeed in attaching it to my access token.

I have setup my identity server with aspnet identity as the provider.

By default my retrieved identity token and access token are returned as follows:

(id token)

{
  "iss": "https://localhost:5001",
  "nbf": 1676383755,
  "iat": 1676383755,
  "exp": 1676384055,
  "aud": "frontend",
  "amr": [
    "pwd"
  ],
  "at_hash": "3TXV8nYmX5Ukn-bmuLPLvQ",
  "sid": "B4FA078C6687CA5F7B1BE31615517880",
  "sub": "c62bd642-3096-43aa-833f-966103dd3071",
  "auth_time": 1676383754,
  "idp": "local"
}

(access token)

{
  "iss": "https://localhost:5001",
  "nbf": 1676383755,
  "iat": 1676383755,
  "exp": 1676387355,
  "scope": [
    "openid",
    "profile"
  ],
  "amr": [
    "pwd"
  ],
  "client_id": "frontend",
  "sub": "c62bd642-3096-43aa-833f-966103dd3071",
  "auth_time": 1676383754,
  "idp": "local",
  "sid": "B4FA078C6687CA5F7B1BE31615517880",
  "jti": "F9FC411122610B702E27039A7D046698"
}

So no userinfo yet so i decided to implement the IProfileService in my identity server solution:

  public class ProfileService : IProfileService
    {
        private readonly IUserClaimsPrincipalFactory<IdentityUser> _userClaimsPrincipalFactory;
        private readonly UserManager<IdentityUser> _userManager;
        private readonly RoleManager<IdentityRole> _roleManager;

        public ProfileService(IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory, UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager)
        {
            _userClaimsPrincipalFactory = userClaimsPrincipalFactory;
            _userManager = userManager;
            _roleManager = roleManager;
        }
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            string sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);

            var userClaims = await _userClaimsPrincipalFactory.CreateAsync(user);

            var claims = userClaims.Claims.ToList();
            claims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
            claims.Add(new Claim(JwtClaimTypes.Name, "testname"));

            context.IssuedClaims = claims;
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            context.IsActive = user != null;
        }
    }

and now my access token have the "name" claim

{
  "iss": "https://localhost:5001",
  "nbf": 1676384026,
  "iat": 1676384026,
  "exp": 1676387626,
  "scope": [
    "openid",
    "profile"
  ],
  "amr": [
    "pwd"
  ],
  "client_id": "frontend",
  "sub": "c62bd642-3096-43aa-833f-966103dd3071",
  "auth_time": 1676384025,
  "idp": "local",
  "name": "testname",
  "sid": "E7E89A3E6A100C2115ED15BDE17CBE66",
  "jti": "80BD171F1AD0F128DA756600D6B96DCE"
}

Should this not be added to the id token instead of the access token? It is my understanding that the id token holds the responsibility for parameters such as name, email etc?

So i guess the question is how I get profile information attached to my id token?

Tried adding profile as default for my client in my identityserver config but now profile information is added to the identity (or access) token:

 public class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
            new[]
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResource
                {
                    Name = "role",
                    UserClaims = new List<string> {"role"}
                }
            };

        public static IEnumerable<ApiScope> ApiScopes =>
            new[]
            {
                new ApiScope("testapi.read"),
                new ApiScope("testapi.write")
            };

        public static IEnumerable<ApiResource> ApiResources =>
            new[]
            {
                new ApiResource("testapi")
                {
                    Scopes = new List<string> { "testapi.read", "testapi.write"},
                    ApiSecrets = new List<Secret> {new Secret("Secret".Sha256())},
                    UserClaims = new List<string> {"role", IdentityServerConstants.StandardScopes.Profile }
                }
            };

        public static IEnumerable<Client> Clients =>
            new[]
            {
                new Client
                {
                    ClientId = "m2m.client",
                    ClientName = "m2m credentials client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("ClientSecret".Sha256())},
                    AllowedScopes = { "testapi.read", "testapi.write" }
                },
                new Client
                {
                    ClientId = "frontend",
                    ClientSecrets = { new Secret("ClientSecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.Code,
                    RedirectUris = { "http://localhost:3000/api/auth/callback/frontend"},
                    FrontChannelLogoutUri = "http://localhost:3000/signout-oidc",   
                    PostLogoutRedirectUris = { "http://localhost:3000/signout-callback-oidc"},
                    AllowOfflineAccess = true,
                    AllowedScopes = {"openid", "profile", "testapi.read", "testapi.write" },
                    RequirePkce = true,
                    RequireConsent= false,
                    AllowPlainTextPkce = false
                }
            };
    }

0 Answers0