I'm setting up a new instance of IdentityServer as an identity provider. While logging in, I want to set some extra, custom claims on my user object. Right now, I'm using the following code:
[HttpPost]
public async Task<IActionResult> ExecuteLogin(string returnUrl, string loginId)
{
TestUser user = Config.GetUsers().Find(x => x.SubjectId == loginId);
if (user != null)
{
var identityServerUser = new IdentityServerUser(user.SubjectId)
{
AdditionalClaims = user.Claims
};
await HttpContext.SignInAsync(identityServerUser);
return Redirect(returnUrl);
}
else
{
return Redirect("Login");
}
}
I expected the AdditionalClaims to show up on the User.Claims object on the receiving application, which I use as following:
[Authorize]
public class HomeController : Controller
{
public IActionResult Index()
{
var claims = User.Claims;
return View(claims);
}
}
However, in the view only the standard claims are visible. Not my additional claims.
In the setup of IdentityServer I specified a client with access to the scope these claims are in, and an IdentityResource with the claimtypes specified in the TestUser. On the receiving application, I specified I want to receive that scope.
What makes that my claims are not visible on the receiving application?
It is not said what type of authentication you are using, but I suppose you want to add the claims to the access_token
from where they can be read by on the API.
AdditionalClaims
on IdentityServerUser
are only added to the cookie in your client.
What you have to do is to create a profile service (https://docs.identityserver.io/en/latest/reference/profileservice.html).
At the simplest it will be something like this:
public class ProfileService : IProfileService
{
private UserService _userService;
public ProfileService(UserService userService)
{
_userService = userService;
}
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = await _userService.GetUserByIdAsync(context.Subject.GetSubjectId());
context.IssuedClaims.AddRange(user.Claims);
return Task.FromResult(0);
}
public Task IsActiveAsync(IsActiveContext context)
{
var user = await _userService.GetUserByIdAsync(context.Subject.GetSubjectId());
context.IsActive = user.IsActive;
return Task.FromResult(0);
}
}
And register it in the Startup.cs:
services.AddIdentityServer()
.AddProfileService<ProfileService>();
These can then be read from the access_token on the API side (if that's what you wanted as it is not clear from the question):
var user = User.Identity as ClaimsIdentity;
var claims = user.Claims;