Summary
I have created a sample project to test the issuing of JWT tokens in an ASP.Net Core applications.
Refer to the Github repo above for the full sample.
In the JwtService.cs class, there is a method called GenerateSecurityToken, which generates the Jwt token.
The Login method of the AccountController calls the JwtService class to generate the token, saves the token in a cookie and also sets another cookie for the user id.
Note: The token is signed with a secret, which is also appended with a user specific salt. The user salt can be invalidated at any point, making the user's token invalid.
The token is also encrypted with an encryption key. This makes the body of the token illegible when inspected in JWT.io. I believe it is called a JWE.
This question discusses the signing and encrypting order.
Issue
I do not want the bearer or any third party to inspect the content of the token. The token's purpose in authentication.
My sample code intercepts the authentication pipeline, and uses the email from the cookie to pull user roles out of the database and creates role claims out of the roles.
A few of you may have figured out the information leak caused by issuing a separate cookie with the email.
Ideally, I want to ONLY issue the JWE token in the cookie.
I want to intercept the authentication pipeline, decrypt the token, use the email claim to get the user salt (from the db) and validate the token.
I have read the documentation, but cannot figure out a way to decrypt the token.
To be honest, I am not even sure of the order of operation (sign then encrypt or encrypt then sign), when the token is issued.
If anyone could even point me to the source code for JwtSecurityTokenHandler
that might be a good start.
TIA
public string GenerateSecurityToken(string email, byte[] salt, string[] roles)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_secret).Concat(salt).ToArray();
byte[] ecKey = new byte[256 / 8];
Array.Copy(Encoding.ASCII.GetBytes(_ecKey), ecKey, 256 / 8);
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = _issuer,
Audience = _audience,
Subject = new ClaimsIdentity(
new List<Claim>
{
new Claim(ClaimTypes.Email, email)
}),
// .Concat(roles.Select(r => new Claim(ClaimTypes.Role, r))).ToArray()),
Expires = DateTime.UtcNow.AddMinutes(double.Parse(_expDate)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
EncryptingCredentials = new EncryptingCredentials(
new SymmetricSecurityKey(
ecKey),
SecurityAlgorithms.Aes256KW,
SecurityAlgorithms.Aes256CbcHmacSha512)
};
var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}