Reputation: 73
I have an API endpoint created using Web API to create a security Token. So the user passes username:password in a Basic Authorization header. The username/password is verified and a Json Web Token is returned.
Now all my other endpoints that do GETs or POSTs I will pass in the JWT in the Authorization header as a BEARER type. I know typically this is BEARER + (jwt) but would it be just as okay to pass BEARER + username:(jwt)
The reason I want to pass the username:(jwt) is when I verify the jwt I also want to pull out the username from the jwt claim and compare it to the username passed in the auth header as an extra check.
Does this approach sound good or should I forget about doing the username check altogether because it doesn't add any extra security?
Upvotes: 2
Views: 2038
Reputation: 3869
You can send the username/userid in the sub claim.
The claims inside of the token are signed. The username/userid(sub) is signed, no need to verify if the username/userid is ok/valid.
In your case the BEARER Username:Token
Username(No signed, can be changed, can't be validated):
Token(claims/header/signature - all content is signed/validated)>
Username/userid outside token don't add extra security.
System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Sub to avoid write "sub" in the claim name. This namespace is located in System.IdentityModel.Tokens.Jwt nuget package.
Upvotes: 1
Reputation: 1319
There is nothing preventing you from adding the username outside of the token, however you can add as many claims to your token as you need and can include the username. These claims can be retrieved from your client application or Web API through the IHttpContextAccessor.
In your client/API you can then do something like this to retrieve the claims:
List<Claim> claims = _context.Request.HttpContext.User.Claims.ToList();
Where _context is of type IHttpContextAccessor.
This obtains the Subject property of your encoded token, which is a ClaimsIdentity consisting of a list of the Claims that have been added when creating your token.
You can add the username outside of the token, however everything you need can be stored more securely and retrieved from the token itself after the client/API has authenticated the bearer token.
In addition, you can use the claims to add extra authorization when accessing other classes within your client/API.
All the other claims types like sub, iat and so on are properties within the token after it is authenticated on your client/API end. What you need to do during token creation is to use the SecurityTokenDescriptor to create the token descriptor like this (abbreviated):
SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, username),
new Claim(JwtRegisteredClaimNames.Sub, username)}),
Expires = DateTime.Now.AddMinutes(expiration_in_minutes),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
You will need to ensure the namespaces are in your source:
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
When I run this to generate the token and then decode the token in https://jwt.io/ in get:
{
"unique_name": "[email protected]",
"sub": "[email protected]",
"nbf": 1622285741,
"exp": 1622287503,
"iat": 1622285741
}
Adding the claim using JwtRegisteredClaimNames.Sub exposes the sub in the token.
Try that and see if it works.
Upvotes: 1