I have been playing around with Asp.Net Core and JWT to learn about JWT. One of my processes is always to make things 'unwork' by removing and altering information. While I did this, I noticed that my project would authorise a token as long time it just contained the following payload (the payload had been genereted by the api and I removed everything, but the parts below):
{
"exp": 1633534580,
"iss": "http://localhost:59921",
"aud": "http://localhost:4200"
}
This would seem like a security issue, since 'iss' and 'aud' would stay constant over time and only the 'exp' would have to be guesses correctly, which would be hard, to get a valid token. Thus, I would like to know how Identity handles a JWT to determine if it is valid and what I, as a developer, could do or implement to increase the security of using JWTs to allow people access to my api's endpoints?
The code that generetes the token is this:
public async Task<IActionResult> Login([FromBody] LoginModel model)
{
var user = await userManager.FindByNameAsync(model.Username);
if (user != null && await userManager.CheckPasswordAsync(user, model.Password))
{
var userRoles = await userManager.GetRolesAsync(user);
var authClaims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
foreach (var userRole in userRoles)
{
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
}
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));
var token = new JwtSecurityToken(
issuer: _configuration["JWT:ValidIssuer"],
audience: _configuration["JWT:ValidAudience"],
expires: DateTime.Now.AddHours(3),
claims: authClaims,
signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
return Unauthorized();
}
My startup file contains this, regarding authenthication.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = Configuration["JWT:ValidAudience"],
ValidIssuer = Configuration["JWT:ValidIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
};
});
The code is based upon this article: https://www.c-sharpcorner.com/article/authentication-and-authorization-in-asp-net-5-with-jwt-and-swagger/
--- Edit --- I guess that for someone to generate a token, they would also need to know the secret key in the signature, which does add some extra security.