0

On login, I am authenticated by Openid connect authorization flow. I get the access token and ID token.

var result = await (_httpContextAccessor.HttpContext 
?? throw new Exception("Call is not within a HttpRequest Context"))
.AuthenticateAsync(IdentityServerConstants
.ExternalCookieAuthenticationScheme); 

result.Properties!.FirstOrDefault(x => x.Key == ".Token.access_token").Value;
result.Properties!.FirstOrDefault(x => x.Key == ".Token.id_token").Value;

The external API I am calling requires a user restricted authentication and we generate an access token as below. And the token generation is successful. I get a access token from this and pass it in the api request as bearer.

var clientAssertion = await CreateClientAssertion();

var postData = new List<KeyValuePair<string, string>>
{
    new("subject_token", idToken),
    new("subject_token_type", "urn:ietf:params:oauth:token-type:id_token"),
    new("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange"),
    new("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
    new("client_assertion", clientAssertion)
};

var token = await RequestToken(postData, _tokenOptions.TokenUrl);

if (token != null)
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);

But the api is responding that I need to add a claim called "org" in the jwt. Now at where do I attach this claim in the JWT?

Should it be in the clientassertion JWT? If so how does the end system recognize the claim when all I am passing at the end would be a Access token.

Gowthami
  • 31
  • 1
  • 3

1 Answers1

0

You could add custom claims at the time of user signin/during the callback.

1. During user signin

        var claims = new List<Claim> {
            new Claim("is_Workspace_owner",isWorkspaceOwner.ToString()),
            new Claim("workspace_owner_email",workspaceOwnerEmail) };

        if (!string.IsNullOrWhiteSpace(workspaceDomain))
        {
            claims.Add(new Claim("workspace_domain", workspaceDomain));
        }

        var identityServerUser = new IdentityServerUser(userId) { AdditionalClaims =  claims } ;
        await httpContext.SignInAsync(identityServerUser);

2. During the callback

Create custom profile service:

using IdentityServer4.Services;

public class ProfileService : IProfileService
{
    private readonly UserManager<ApplicationUser> _userManager;

    public ProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        ApplicationUser user = await _userManager.GetUserAsync(context.Subject);
        
        var claims = new List<Claim>
        {
            new Claim("has_password", (!string.IsNullOrWhiteSpace(user.PasswordHash)).ToString(), ClaimValueTypes.Boolean),
            new Claim("email", user.Email),
            workspaceOwnerClaim!
        };

        // Get the user's roles
        var roles = await _userManager.GetRolesAsync(user!);
        var roleClaims = roles.Select(role => new Claim(JwtClaimTypes.Role, role));
        claims.AddRange(roleClaims);

        context.IssuedClaims.AddRange(claims);
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        //var user = await _userManager.GetUserAsync(context.Subject);

        //context.IsActive = (user != null);
        
        context.IsActive = true;

    }
}

And register profile service:

builder.Services.AddIdentityServer(x =>
{
    x.UserInteraction.ErrorUrl = "error/index";
    x.Authentication.CookieSameSiteMode = Microsoft.AspNetCore.Http.SameSiteMode.None;
})
//  Identity server settings ...
.AddProfileService<ProfileService>();