Publish Claims in the IdToken in IdentityServer4
By default, claims are published in the access token. However, there may be some claims that you may wish to publish in the Id Token.
1 - Create an IProfileService
public class IdentityProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
private readonly UserManager<ApplicationUser> _userManager;
public IdentityProfileService(IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, UserManager<ApplicationUser> userManager)
{
_claimsFactory = claimsFactory;
_userManager = userManager;
}
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
context.AddRequestedClaims(context.Subject.Claims);
// Add claims to access token
if (context.Caller == "ClaimsProviderAccessToken")
{
context.IssuedClaims.Add(new Claim("custom1", "custom1"));
}
// Add identity token claims
if (context.Caller == "ClaimsProviderIdentityToken") (1)
{
context.IssuedClaims.Add(new Claim("custom1", "custom1"));
context.IssuedClaims.Add(new Claim("custom2", "custom2"));
}
// Add userinfo endpoint claims
if (context.Caller == "UserInfoEndpoint")
{
context.IssuedClaims.Add(new Claim("custom1", "custom1"));
context.IssuedClaims.Add(new Claim("custom2", "custom2"));
}
return Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}
1 | The GetProfileDataAsync method gets called multiple times for each type of context.caller - "ClaimsProviderAccessToken", "ClaimsProviderIdentityToken", and "UserInfoEndpoint". Here we add a claim when the caller is "ClaimsProviderIdentityToken" and these claims show up in the IdToken. |
2 - In Startup.cs, add the IProfileService to the services collection.
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryIdentityResources(Configs.IdentityServerConfig.GetIdentityResources())
.AddInMemoryApiResources(Configs.IdentityServerConfig.GetApiResources())
.AddInMemoryClients(Configs.IdentityServerConfig.GetClients())
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<IdentityProfileService>() (1)
1 | Add the IdentityProfileService to the services collection. |
3 The client should have AlwaysIncludeUserClaimsInIdToken = true
set
public static IEnumerable<Client> GetClients()
{
//Create clients list like webui, console applications and...
List<Client> clients = new List<Client>();
//Add WebUI client
Client webUi = new Client();
webUi.ClientId = "U2EQlBHfcbuxUo";
webUi.ClientSecrets.Add(new Secret("TbXuRy7SSF5wzH".Sha256()));
webUi.ClientName = "WebUI";
webUi.AllowedGrantTypes = GrantTypes.HybridAndClientCredentials;
webUi.RequireConsent = false;
webUi.AllowOfflineAccess = true;
webUi.AlwaysSendClientClaims = true;
webUi.AlwaysIncludeUserClaimsInIdToken = true; (1)
webUi.AllowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
webUi.AllowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
webUi.AllowedScopes.Add("ApplicationApi");
webUi.AllowedScopes.Add("DefinitionApi");
webUi.AllowedScopes.Add("FFAPI");
webUi.ClientUri = "http://localhost:5003";
webUi.RedirectUris.Add("http://localhost:5003/signin-oidc");
webUi.PostLogoutRedirectUris.Add("http://localhost:5003/signout-callback-oidc");
clients.Add(webUi);
}
1 | AlwaysIncludeUserClaimsInIdToken is set to true . |