Welcome to today’s post.
In this post I will be showing how to embed user roles within JWT token claims within a custom identity provider API using .NET Core Identity.
The use of roles within web application security allows various sections of the application to be blocked from default user access. The use of roles is used to permit authorized access only to users that are in a role or set of roles.
Recommended Practices when Transmitting Authorization Roles
It is tempting to conditionally hardcode encode the roles into a client application to open access to protected areas. However, this is a bad practice that allows anyone with access to deployed scripts to modify client script and alter the authorization of the application completely!
The recommended practice when implementing role-based access in web client applications is to never hardcode the roles into the application. It should be done based on the secure token that is passed into the application request context. In a previous post I showed how management of user roles are implemented within a custom Web API identity service. Once roles are defined for a particular user, they can then be retrieved for that user. This means we can store user roles within the JSON payload of a secure JWT token that is returned following authentication.
When transmitting roles to web applications, it should be done through a secure payload, and that secure payload within a secure token. Once we have decrypted and unpacked the token payload and retrieved the roles from the payload, we can then use them to control authorization within our web client.
When requesting a JWT authentication token from our authentication (token generation) API method within our identity service, the resulting token will contain role type claims. These role type claims are of type:
ClaimTypes.Role
As our token is encrypted, provided our secret is not known to the consumer of our service, the roles will not be known until the token is decoded by the application. As the roles are within the encrypted token, they will never be visible until the entire JWT token payload is decrypted on the client web application.
When our client application decodes this token, the roles can be read in and used for application side authorization.
In a previous post I discussed implementation of a token manager within our identity service API. Today I will be amending our token manager to return user roles that can be useful within our client applications.
In a previous post I showed how management of user roles are implemented within a custom Web API identity service.
Amending Token Generation to Return User Roles
In the custom identity service, I had a TokenManager class that is used to generate tokens. The original implementation returned a JWT token which is decoded on the web client to retrieve the token, which is then validated to authenticate the user within the application.
The revised version includes code to embed the user roles into the Claims role types, then add the claims to the token descriptor. A token is then generated from the token descriptor, which is then returned.
Below is the revised GenerateToken() method for our token manager:
public string GenerateToken(string username)
{
byte[] key = Convert.FromBase64String(_appConfiguration.Secret);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
SymmetricSecurityKey securityKey = new SymmetricSecurityKey(key);
SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, username)}),
Expires = DateTime.Now.AddMinutes(30),
SigningCredentials = new SigningCredentials(new
SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
// build claims user roles
var userRoles =
_userRoleService.GetUserRoles(username).GetAwaiter();
var claims = new List<Claim>();
foreach (var userRole in userRoles.GetResult())
{
claims.Add(new Claim(ClaimTypes.Role, userRole));
}
descriptor.Subject.AddClaims(claims);
JwtSecurityToken token =
handler.CreateJwtSecurityToken(descriptor);
return handler.WriteToken(token);
}
The method we use to return the user roles, GetUserRoles() is shown below:
public async Task<List<string>> GetUserRoles(string userName)
{
var user = await userManager.FindByEmailAsync(userName);
IList<string> roles = await userManager.GetRolesAsync(user);
if (roles != null)
return roles.ToList();
return new List<string>();
}
Each claims identity consists of a collection of claims of type IEnumerable<System.Security.Claims.Claim>, which has the following properties:
Issuer | This is the name of the entity that issued the claim. |
Subject | This is the subject of the claim, normally the user that requested access to the resource. |
Type | This is semantic information about the claim, such as Email, PostalCode, Surname etc. |
Value | This is the value of the claim in string format. |
Each claim is then constructed using the claim type of Role and value, which is the role. The claims are then added to a list of claims.
We then add the list of claims to the Subject property of our SecurityTokenDesciptor and use the ClaimsIdentity method:
AddClaims(IEnumerable<System.Security.Claims.Claim>);
The roles are stored and retrieved from the table AspNetUserRoles from the ASP.NET Identity UserManager method :
GetRolesAsync(string);
With the above approach, the hard work of packaging a token with the roles is done from the identity service. All that is needed is for the web client to retrieve the roles.
In a future post I will show how to retrieve the roles from a JWT token from our client application or API service method.
That’s all for today’s post.
I hope this post has been useful and informative.
Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.