Home > OS >  JWT Authentication And Authorization In .NET 6.0 401Unauthorized Error
JWT Authentication And Authorization In .NET 6.0 401Unauthorized Error

Time:07-21

i am creating a token and it does not accept the token I created, the error code 401 returns

appsettings.json

{
  "TokenOptions": {
    "Audience": "https://localhost:7098",
    "Issuer": "https://localhost:7098",
    "AccessTokenExpiration": 500,
    "SecurityKey": "mysecretkeymysecretkey"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

TokenOptions.cs

namespace Shared.Utilities.Security.Jwt;

public class TokenOptions
{
    public string Audience { get; set; }
    public string Issuer { get; set; }
    public int AccessTokenExpiration { get; set; }
    public string SecurityKey { get; set; }
}

JwtHelper.cs

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Shared.Entities.Concrete;
using Shared.Extensions;
using Shared.Utilities.Security.Encyption;

namespace Shared.Utilities.Security.Jwt;

public class JwtHelper : ITokenHelper
{
    public IConfiguration Configuration { get; }
    private TokenOptions _tokenOptions;
    private DateTime _accessTokenExpiration;

    public JwtHelper(IConfiguration configuration)
    {
        Configuration = configuration;
        _tokenOptions = Configuration.GetSection(key: "TokenOptions").Get<TokenOptions>();
    }

    public AccessToken CreateToken(User user, List<OperationClaim> operationClaims)
    {
        _accessTokenExpiration = DateTime.Now.AddMinutes(_tokenOptions.AccessTokenExpiration);
        var securityKey = SecurityKeyHelper.CreateSecurityKey(_tokenOptions.SecurityKey);
        var signingCredentials = SigningCredentialsHelper.CreateSigningCredentials(securityKey);
        var jwt = CreateJwtSecurityToken(_tokenOptions, user, signingCredentials, operationClaims);
        var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
        var token = jwtSecurityTokenHandler.WriteToken(jwt);

        return new AccessToken
        {
            Token = token,
            Expiration = _accessTokenExpiration
        };

    }

    public JwtSecurityToken CreateJwtSecurityToken(TokenOptions tokenOptions, User user, SigningCredentials signingCredentials, List<OperationClaim> operationClaims)
    {
        var Jwt = new JwtSecurityToken(
            issuer: tokenOptions.Issuer,
            audience: tokenOptions.Audience,
            expires: _accessTokenExpiration,
            notBefore: DateTime.Now,
            claims: SetClains(user, operationClaims),
            signingCredentials: signingCredentials
            );
        return Jwt;
    }

    private IEnumerable<Claim> SetClains(User user, List<OperationClaim> operationClaims)
    {
        var claims = new List<Claim>();
        claims.AddNameIdentifier(user.Id.ToString());
        claims.AddEmail(user.Email);
        claims.AddName($"{user.FirstName} {user.LastName}");
        claims.AddRole(operationClaims.Select(c => c.Name).ToArray());
        return claims;
    }

}

ITokenHelper.cs

using Shared.Entities.Concrete;

namespace Shared.Utilities.Security.Jwt;

public interface ITokenHelper
{
    AccessToken CreateToken(User user, List<OperationClaim> operationClaims);
}

AccessToken.cs

namespace Shared.Utilities.Security.Jwt
{
    public class AccessToken
    {
        public string Token { get; set; }
        public DateTime Expiration { get; set; }
    }
}

HashingHelper.cs

using System.Text;

namespace Shared.Utilities.Security.Hashing;

public class HashingHelper
{
    public static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
    {
        using (var hmac = new System.Security.Cryptography.HMACSHA512())
        {
            passwordSalt = hmac.Key;
            passwordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password));
        }
    }

    public static bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
    {
        using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
        {
            var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password));
            for (int i = 0; i < computedHash.Length; i  )
            {
                if (computedHash[i] != passwordHash[i])
                {
                    return false;
                }
            }
        }
        return true;
    }
}   

SigningCredentialsHelper.cs

using Microsoft.IdentityModel.Tokens;

namespace Shared.Utilities.Security.Encyption;

public class SigningCredentialsHelper
{
    public static SigningCredentials CreateSigningCredentials(SecurityKey securityKey)
    {
        return new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
    }
}

SecurityKeyHelper.cs

using System.Text;
using Microsoft.IdentityModel.Tokens;

namespace Shared.Utilities.Security.Encyption;

public class SecurityKeyHelper
{
    public static SecurityKey CreateSecurityKey(string securityKey)
    {
        return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey));
    }
}

ClaimExtensions.cs

using System.Security.Claims;
using Microsoft.IdentityModel.JsonWebTokens;

namespace Shared.Extensions;

public static class ClaimExtensions
{
    public static void AddEmail(this ICollection<Claim> claims, string email)
    {
        claims.Add(new Claim(type: JwtRegisteredClaimNames.Email, value: email));
    }
    public static void AddName(this ICollection<Claim> claims, string name)
    {
        claims.Add(new Claim(type: ClaimTypes.Name, value: name));
    }
    public static void AddNameIdentifier(this ICollection<Claim> claims, string nameIdentifier)
    {
        claims.Add(new Claim(type: ClaimTypes.NameIdentifier, value: nameIdentifier));
    }
    public static void AddRole(this ICollection<Claim> claims, string[] roles)
    {
        roles.ToList().ForEach(role => claims.Add(new Claim(type: ClaimTypes.Role, value: role)));
    }
}

AutofacBusinessModule.cs

using Autofac;
using Data.Abstract;
using Data.Concrete.EntityFramework;
using Services.Abstract;
using Services.Concrete;
using Shared.Utilities.Security.Jwt;

namespace Services.DependencyResolvers.Autofac
{
    public class AutofacBusinessModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<ProductManager>().As<IProductService>();
            builder.RegisterType<EfProductRepository>().As<IProductRepository>();

            builder.RegisterType<CategoryManager>().As<ICategoryService>();
            builder.RegisterType<EfCategoryRepository>().As<ICategoryRepository>();

            builder.RegisterType<UserManager>().As<IUserService>();
            builder.RegisterType<EfUserRepository>().As<IUserRepository>();

            builder.RegisterType<AuthManager>().As<IAuthService>();

            builder.RegisterType<JwtHelper>().As<ITokenHelper>();
        }
    }
}


AuthController.cs

using Entities.Dtos;
using Microsoft.AspNetCore.Mvc;
using Services.Abstract;

namespace WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private IAuthService _authService;

        public AuthController(IAuthService authService)
        {
            _authService = authService;
        }

        [HttpPost("login")]
        public async Task<IActionResult> Login(UserForLoginDto userForLoginDto)
        {
            var userToLogin = await _authService.Login(userForLoginDto);

            if (!userToLogin.IsSuccess)
                return BadRequest(userToLogin.Message);

            var result = await _authService.CreateAccessToken(userToLogin.Data);

            if (result.IsSuccess)
                return Ok(result.Data);

            return BadRequest(result.Message);
        }

        [HttpPost("register")]
        public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
        {
            var userExists = await _authService.UserExists(userForRegisterDto.Email);

            if (!userExists.IsSuccess)
                return BadRequest(userExists.Message);

            var registerResult = await _authService.Register(userForRegisterDto);

            var result = await _authService.CreateAccessToken(registerResult.Data);

            if (result.IsSuccess)
                return Ok(result.Data);

            return BadRequest(result.Message);
        }
    }
}


Program.cs

using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Services.DependencyResolvers.Autofac;
using Shared.Utilities.Security.Encyption;
using Shared.Utilities.Security.Jwt;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer<ContainerBuilder>(builder =>
{
    builder.RegisterModule(new AutofacBusinessModule());
});

var tokenOptions = builder.Configuration.GetSection(key: "TokenOptions").Get<TokenOptions>();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {

        ValidIssuer = tokenOptions.Issuer,
        ValidAudience = tokenOptions.Audience,
        IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),

        ValidateIssuerSigningKey = true,
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidateLifetime = true,
        ClockSkew = TimeSpan.Zero
    };
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthentication();

app.UseAuthorization();

app.MapControllers();

app.Run();

CreateTokenPostman.cs enter image description here

401ErrorPostman.cs enter image description here

CodePudding user response:

I have compared your code with this repo. And I find something, it maybe useful to you.

You should change your code like below.

options.TokenValidationParameters = new TokenValidationParameters
{

    ValidIssuer = tokenOptions.Issuer,
    ValidAudience = tokenOptions.Audience,
    IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),

    ValidateIssuerSigningKey = true,
    ValidateAudience = true,
    ValidateIssuer = true,
    ValidateLifetime = true,
    //ClockSkew = TimeSpan.Zero
};

Or

options.TokenValidationParameters = new TokenValidationParameters
{

    ValidIssuer = tokenOptions.Issuer,
    ValidAudience = tokenOptions.Audience,
    IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),

    ValidateIssuerSigningKey = true,
    ValidateAudience = true,
    ValidateIssuer = true,
    ValidateLifetime = true,
    ClockSkew = TimeSpan.Zero,
    // add this line
    RequireExpirationTime = true
};

CodePudding user response:

Thanks. I found the error related to the latest version of jwt. the error was fixed when i downloaded the old version of jwt

  • Related