The token is generated through this method:
private string GenerateJwtToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var base64Key = _configuration["Jwt:Secret"];
try
{
var key = Convert.FromBase64String(base64Key);
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = _configuration["Jwt:Issuer"],
Audience = _configuration["Jwt:Audience"],
Subject = new ClaimsIdentity(
new Claim[]
{
new Claim(ClaimTypes.Name, user.Email),
new Claim("UserId", user.ID.ToString())
}
),
Expires = DateTime.UtcNow.AddDays(14),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature
)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
catch (FormatException ex)
{
Console.WriteLine($"error converting Base64 string: {ex.Message}");
return null;
}
}
I checked on jwt.io and it says the token generated is valid.
When I use thunderclient to my /user endpoint to get the user by passing the JWT token in the header then I get Status: 401 Unauthorized.
Here is my post method:
[HttpPost]
[Authorize]
public async Task<ActionResult<UserDTO>> GetUserDTO()
{
Console.WriteLine("I GET USER");
try
{
var jwt = HttpContext.Request.Headers["Authorization"]
.ToString()
.Replace("Bearer ", string.Empty);
Console.WriteLine(jwt);
if (string.IsNullOrWhiteSpace(jwt))
{
return BadRequest("JWT token is missing.");
}
var loggedInUser = _userService.GetByJWT(jwt);
if (loggedInUser == null)
{
return BadRequest("Failed to get user.");
}
return Ok(loggedInUser.FirstName);
}
catch (Exception e)
{
return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
}
}
When I remove [Authorize]
then it works and it can resolve the id from the JWT bearer.
In program.cs
I have my authorize schema and tried to change it and see if it's something wrong with my issuer or audience? I set my issuer value as my application name and the audience value as API since it's the API that will use it. Is that correct? Here is the schema:
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])
),
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"]
};
});
builder.Services.AddAuthorization();
Why do I get unauthorized?
EDITED Here is how I have tried setting the header / authorizarion
The problem is that you use two different keys, see the following lines:
var key = Convert.FromBase64String(base64Key); //used to generate a jwt
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])
) // used to check a jwt
Basically Encoding.UTF8.GetBytes
and Convert.FromBase64String(base64Key)
don't return the same byte[]
for the same string
Change the line to the following in your .AddJwtBearer
method call
IssuerSigningKey = new SymmetricSecurityKey(
Convert.FromBase64String(builder.Configuration["Jwt:Secret"])
) // used to check a jwt