I am trying to unlock my endpoints (Controllers) with my JWT token that is sent to the user when they login. At the moment the register and login works and the user is sent a JWT token. However when I use postman or my Mobile application to send the JWT to the API I get a 401 Unauthorized error. I am using Asp.net 6 web API. I have added my Authentication Controller and my program.cs. I have my JWT key in my appsettings.json as well as the issuer and Audience. I am sure my error is in my program.cs
AuthController
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using VelocityNetAPI.Models;
using System.Security.Cryptography;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using VelocityNetAPI.Data;
using Microsoft.AspNetCore.Authorization;
namespace VelocityNetAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
public static User user = new User();
private readonly IConfiguration configuration;
private readonly VelocityNetAPIContext context;
public AuthController(IConfiguration configuration, VelocityNetAPIContext context)
{
this.configuration = configuration;
this.context = context;
}
[HttpPost("Register")]
public async Task<ActionResult<User>> Register(UserDto request)
{
CreatePasswordHash(request.Password, out byte[] passwordHash, out byte[] passwordSalt);
user.Name = request.Username;
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
user.Role = "User";
context.User.Add(user);
await context.SaveChangesAsync();
return Ok(user);
}
[HttpPost("Login")]
public async Task<ActionResult<string>> Login(UserDto request)
{
//search for user
var user = context.User.FirstOrDefault(u => u.Name == request.Username);
if (user == null)
{
return BadRequest("User not found");
}
if(!VerifyPasswordHash(request.Password, user.PasswordHash, user.PasswordSalt))
{
return BadRequest("Wrong Password");
}
string token = CreateToken(user);
return Ok(token);
}
private string CreateToken(User user)
{
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Name),
new Claim(ClaimTypes.Role, user.Role),
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(configuration["Jwt:key"]));
var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512);
var token = new JwtSecurityToken(
claims: claims,
expires: DateTime.Now.AddDays(1),
signingCredentials: cred);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
}
private void CreatePasswordHash(String password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (HMACSHA512 hmac = new HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (HMACSHA512 hmac = new HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
return computedHash.SequenceEqual(passwordHash);
}
}
}
}
Program.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using VelocityNetAPI.Data;
using Microsoft.IdentityModel.Tokens;
using System.Configuration;
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authorization;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<VelocityNetAPIContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("VelocityNetAPIContext")));
var conf = builder.Configuration;
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = true;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = conf["Jwt:Issuer"].ToString(),
ValidAudience = conf["Jwt:Audience"].ToString(),
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(conf["Jwt:Key"]))
};
});
//Configuration.GetSection("AppSettings:Token").Value)
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
var 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();
Let me know if you need more info Cheers Everyone
CodePudding user response:
You set ValidateIssuer
and ValidateAudience
true. But in your CreateToken
method you do not use Issuer
and Audience
to generate token.
You can change your CreateToken
method like below:
var token = new JwtSecurityToken(configuration["Jwt:Issuer"],
configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddDays(1),
signingCredentials: cred);