skip to Main Content

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);
    
}

enter image description here

I tried commenting out https enforcement (app.UseHttpsRedirection(); in Program.cs), but that didn’t help

2

Answers


  1. 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:

    string username = context.User.Claims.Where(c => c.Type == ClaimTypes.Name).Select(a => a.Value.ToString()).FirstOrDefault();
    

    Check also the ClaimsPrincipalExtensions example in this answer

    Login or Signup to reply.
  2. IssuerSigningKey in program.cs and SymmetricSecurityKey in TokenService must be the same. You need to change addAuthentication in Program.cs to:

    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 = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AuthOptions.SECRETKEY)), // it must be the same with SymmetricSecurityKey in TokenService 
            
            ValidateIssuerSigningKey = true,
        };
        
        
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search