❔ ✅ Jwt auth not working

No description
No description
9 Replies
blueberriesiftheywerecats
Program.cs
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.Configure<MyOptions>(builder.Configuration.GetSection(nameof(MyOptions)));

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

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["MyOptions:JWT_ISSUER"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
builder.Configuration["MyOptions:SECRET_KEY"]!))
};
});

builder.Services.AddAuthorization();

builder.Services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<AppDbContext>();

builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});

builder.Services.AddScoped<JwtService>();

var app = builder.Build();

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

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.Configure<MyOptions>(builder.Configuration.GetSection(nameof(MyOptions)));

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

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["MyOptions:JWT_ISSUER"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
builder.Configuration["MyOptions:SECRET_KEY"]!))
};
});

builder.Services.AddAuthorization();

builder.Services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<AppDbContext>();

builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});

builder.Services.AddScoped<JwtService>();

var app = builder.Build();

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

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();
JwtService.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi.Entities;

namespace TestAuth.WebApi.Services;

public class JwtService
{
private readonly UserManager<AppUser> _userManager;
private readonly IOptions<MyOptions> _options;

public JwtService(UserManager<AppUser> userManager, IOptions<MyOptions> options)
{
_userManager = userManager;
_options = options;
}

public async Task<string> GenerateJwtToken(AppUser user)
{
var claims = new Claim[]
{
new (JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new (JwtRegisteredClaimNames.Email, user.Email!),
new (ClaimTypes.Role, user.Role.ToString()),
new (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};

var authSecret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.SECRET_KEY));

var tokenObject = new JwtSecurityToken(
issuer: _options.Value.JWT_ISSUER,
expires: DateTime.Now.AddDays(60),
claims: claims,
signingCredentials: new SigningCredentials(authSecret, SecurityAlgorithms.HmacSha256)
);

string token = new JwtSecurityTokenHandler().WriteToken(tokenObject);

return token;
}
}
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using LadaServ.Application.Common;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using TestAuth.WebApi.Entities;

namespace TestAuth.WebApi.Services;

public class JwtService
{
private readonly UserManager<AppUser> _userManager;
private readonly IOptions<MyOptions> _options;

public JwtService(UserManager<AppUser> userManager, IOptions<MyOptions> options)
{
_userManager = userManager;
_options = options;
}

public async Task<string> GenerateJwtToken(AppUser user)
{
var claims = new Claim[]
{
new (JwtRegisteredClaimNames.NameId, user.Id.ToString()),
new (JwtRegisteredClaimNames.Email, user.Email!),
new (ClaimTypes.Role, user.Role.ToString()),
new (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};

var authSecret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.SECRET_KEY));

var tokenObject = new JwtSecurityToken(
issuer: _options.Value.JWT_ISSUER,
expires: DateTime.Now.AddDays(60),
claims: claims,
signingCredentials: new SigningCredentials(authSecret, SecurityAlgorithms.HmacSha256)
);

string token = new JwtSecurityTokenHandler().WriteToken(tokenObject);

return token;
}
}
AccountController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.DTOs;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;

namespace TestAuth.WebApi.Controllers;

[ApiController]
[AllowAnonymous]
[Route("accounts")]
public class AccountController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly RoleManager<AppRole> _roleManager;
private readonly JwtService _jwtService;

public AccountController(UserManager<AppUser> userManager, RoleManager<AppRole> roleManager, JwtService jwtService)
{
_userManager = userManager;
_roleManager = roleManager;
_jwtService = jwtService;
}

[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
var user = new AppUser()
{
Role = RoleEnum.User,
Email = registerDto.Email
};

var result = await _userManager.CreateAsync(user, registerDto.Password!);

var roleExist = await _roleManager.RoleExistsAsync(user.Role.ToString());
if (!roleExist)
{
await _roleManager.CreateAsync(new AppRole { Name = user.Role.ToString() });
}

await _userManager.AddToRoleAsync(user, user.Role.ToString());

var token = await _jwtService.GenerateJwtToken(user!);
return new JsonResult(new { email = user.Email, token = token });
}
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.DTOs;
using TestAuth.WebApi.Entities;
using TestAuth.WebApi.Services;

namespace TestAuth.WebApi.Controllers;

[ApiController]
[AllowAnonymous]
[Route("accounts")]
public class AccountController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly RoleManager<AppRole> _roleManager;
private readonly JwtService _jwtService;

public AccountController(UserManager<AppUser> userManager, RoleManager<AppRole> roleManager, JwtService jwtService)
{
_userManager = userManager;
_roleManager = roleManager;
_jwtService = jwtService;
}

[HttpPost]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
var user = new AppUser()
{
Role = RoleEnum.User,
Email = registerDto.Email
};

var result = await _userManager.CreateAsync(user, registerDto.Password!);

var roleExist = await _roleManager.RoleExistsAsync(user.Role.ToString());
if (!roleExist)
{
await _roleManager.CreateAsync(new AppRole { Name = user.Role.ToString() });
}

await _userManager.AddToRoleAsync(user, user.Role.ToString());

var token = await _jwtService.GenerateJwtToken(user!);
return new JsonResult(new { email = user.Email, token = token });
}
}
TestController.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.Entities;

namespace TestAuth.WebApi.Controllers;

[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("get1")]
public string Get1() => "authed";

[Authorize(Roles = nameof(RoleEnum.User))]
[HttpGet("get2")]
public string Get2() => "user";

[AllowAnonymous]
[HttpGet("get3")]
public string Get3() => "anonymous";
}
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TestAuth.WebApi.Entities;

namespace TestAuth.WebApi.Controllers;

[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("get1")]
public string Get1() => "authed";

[Authorize(Roles = nameof(RoleEnum.User))]
[HttpGet("get2")]
public string Get2() => "user";

[AllowAnonymous]
[HttpGet("get3")]
public string Get3() => "anonymous";
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",

"MyOptions": {
"JWT_ISSUER": "https://localhost:7267",
"SECRET_KEY": "my-32-character-ultra-secure-and-ultra-long-secret-AAAultra-long-secret-AAA"
},

"ConnectionStrings": {
"DefaultConnection": "Data Source=helloapp.db"
}
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",

"MyOptions": {
"JWT_ISSUER": "https://localhost:7267",
"SECRET_KEY": "my-32-character-ultra-secure-and-ultra-long-secret-AAAultra-long-secret-AAA"
},

"ConnectionStrings": {
"DefaultConnection": "Data Source=helloapp.db"
}
}
Exeteres
Exeteres14mo ago
it seems that you are not specifying an audience while creating JWT token specify it in new JwtSecurityToken or disable it's validation in options.TokenValidationParameters: ValidateAudience = false
blueberriesiftheywerecats
DAMN it worked finally thx, what does even audience stands for?
Exeteres
Exeteres14mo ago
for consumer of the token issuer is something who creates the token (auth service) and audience (or multiple audiences) is something that should verify the user authentication and claims (roles, for example) both are not required btw the only thing that is essential for JWT to work is valid signature even expiration date is not required, but highly recommended
blueberriesiftheywerecats
so audience need frontend server url?
Exeteres
Exeteres14mo ago
yes like something that provides some services for an authenticated user without dealing with his credentials
blueberriesiftheywerecats
ok, thx
Exeteres
Exeteres14mo ago
it is not required to be a url though it can be any string and issuer can also be any string but usually it is a url, yes it is all up to you how to organize this stuff and I already mentioned that it is not required at all
Accord
Accord13mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server