I am a noob, trying to do JWT the simplest possible way on a .NET Core 6 Web API project, but I can't even get it to work.
Requirement: You need to be logged in to call the GetProductList API.
(I am testing this on Swagger that comes with the project)
FYI, my Login controller: (working as intended)
[HttpPost("login")]
public async Task<ActionResult> Login(LoginDto request)
{
var user = GetUserFromRequest(request);
if (user == null)
return BadRequest("Invalid credentials.");
string jwt = CreateJwtToken(user.Id.ToString());
Response.Cookies.Append(COOKIE_JWT, jwt, _cookieOptions);
return Ok();
}
[HttpGet("user")]
public IActionResult GetUser()
{
try
{
var jwt = Request.Cookies[COOKIE_JWT];
var userId = VerifyJwtAndGetUserId(jwt);
return Ok(GetUserById(userId));
}
catch(Exception ex)
{
return Unauthorized();
}
}
public static string CreateJwtToken(string userId)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWT_KEY));
var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
var token = new JwtSecurityToken(
issuer: userId,
expires: DateTime.Now.AddDays(365),
signingCredentials: cred
);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
}
public static string VerifyJwtAndGetUserId(string jwt)
{
var tokenHandler = new JwtSecurityTokenHandler();
tokenHandler.ValidateToken(jwt, new TokenValidationParameters {
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWT_KEY)),
ValidateIssuerSigningKey = true,
ValidateIssuer = false,
ValidateAudience = false
}, out SecurityToken validatedToken);
string userId = validatedToken.Issuer;
return userId;
}
The question is, how can I make the [Authorize] attribute work?
[HttpGet("list")]
//[Authorize]
public async Task<ActionResult<List<Product>>> GetProductList()
{
return Ok(GetProducts());
}
The above works, but adding [Authorize] attribute gives a 401 with the following header: (while GetUser above is fine)
content-length: 0
date: Mon,13 Jun 2022 23:27:32 GMT
server: Kestrel
www-authenticate: Bearer
This is what's in my Program.cs: (maybe this is wrong?)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters { // similar to the one in controller
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWT_KEY)),
ValidateIssuerSigningKey = true,
ValidateIssuer = false,
ValidateAudience = false
};
options.Events = new JwtBearerEvents { // https://spin.atomicobject.com/2020/07/25/net-core-jwt-cookie-authentication/
OnMessageReceived = ctx => {
ctx.Token = ctx.Request.Cookies["jwt"];
return Task.CompletedTask;
}
};
});
SOLUTION:
Move app.UseAuthentication(); above app.UserAuthorization();.
Summary
FrontEnd
According to JWT Introduction as below
So you need to add a header
Authorization: Bearer <token>in your request on frontEnd.a simple example at frontEnd. In this example the
yourApiUrlshould be yourlistapi route.getCookieValue function
then your request will have the authorization header with a prefix [Bearer].

a picture from my browser's dev tool.
and then the
[Authorize]attribute should workBackEnd
Maybe it is not the problem at frontEnd, then you can check the backEnd's code.
Some code example at backEnd
.NET 6 WebApiabout generate or examine the JWT tokenGenerateToken function
Use to generate token when sign-in controller
Program.cs
.NET6 WebApi's setting inProgram.csabout examine Jwt token.[NOTICE]: the method
builder.Services.AddAuthorization();MUST below thebuilder.Services.AddAuthenticationmethod, or will result error.Easy Test by thunder client of VsCode
Bearera simple image of thunder client