I’m making my first API using the ASP .NET 7 framework. I am using JWT token. I have this problem that the authorize tag always returns Unauthorize. I have checked that the correct access token comes from the client, and the only problem is that the tag can’t validate it. I am attaching the structure of my project in PNG. Here is code of my Program.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using WebApi.Models;
using WebApi.Services;
using WebApi;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<UserContext>(opt =>
opt.UseInMemoryDatabase("UserList"));
builder.Services.AddScoped<ITokenService, TokenService>();
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = true,
ValidIssuer = AuthOptions.ISSUER,
ValidateAudience = true,
ValidAudience = AuthOptions.AUDIENCE,
ValidateLifetime = true, //make true after tests
IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
ValidateIssuerSigningKey = true,
};
});
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
app.UseSwagger();
app.UseSwaggerUI();
}
//app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Now my token generation:
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace WebApi.Services {
public class TokenService : ITokenService {
public string GenerateAccessToken(string username) {
List<Claim> claims = new() {
new Claim(ClaimTypes.Name, username)
};
SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(AuthOptions.SECRETKEY));
SigningCredentials creds = new(key, SecurityAlgorithms.HmacSha256);
JwtSecurityToken token = new(
issuer: AuthOptions.ISSUER,
audience: AuthOptions.AUDIENCE,
claims: claims,
expires: DateTime.UtcNow.AddMinutes(AuthOptions.ACCESSTOKENLIFETIME),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
And the place in my controller where I’m trying to use [Authorize]
[HttpGet("{id}")]
[Authorize]
public async Task<IActionResult> GetUserById(int id) {
string username = HttpContext.User.Identity.Name;
string token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", "");
_logger.LogInformation(username + " username");
_logger.LogInformation(token + " token");
User? user = await _dbContext.Users.FirstOrDefaultAsync(u => u.email == username);
if (user == null) {
return NotFound("User not found");
}
int userId = user.id;
if (userId != id) {
return Unauthorized("Unauthorized");
}
string newAccessToken = _tokenService.GenerateAccessToken(user.username);
UserInfoResponse userInfo = new() {
username = user.username,
id = user.id,
avatar = user.avatar,
accessToken = newAccessToken
};
return Ok(userInfo);
}
I tried commenting out https enforcement (app.UseHttpsRedirection(); in Program.cs), but that didn’t help
2
Answers
You are checking for access based on
HttpContext.User.Identity.Name
, however you are adding the username as a claim.Try checking for the username like this:
Check also the
ClaimsPrincipalExtensions
example in this answerIssuerSigningKey in program.cs and SymmetricSecurityKey in TokenService must be the same. You need to change addAuthentication in Program.cs to: