I'm trying to implement jwt to my project. And it was working before i changed the code. This changes doesn't affect the authorization but somehow tokens doesn't work anymore.
When I check the token from jwt.io, it says "invalid signature". And when I try to execute a request using Swagger, responds says
content-length: 0
date: Fri,02 Sep 2022 10:09:12 GMT
server: Kestrel
www-authenticate: Bearer error="invalid_token"
x-firefox-spdy: h2
Secret : tx9mcA4gnbigtP7ZRECnfhk9tWsHM9ZtXqbuFYWM23D3PMdRKwh74e24swqvrTh5
API/Programs.cs
using System.Text;
using BlogProject.Business.MapperProfile;
using BlogProject.Business.Services.AuthenticationService;
using BlogProject.Business.Services.CommentService;
using BlogProject.Business.Services.PostService;
using BlogProject.Business.Services.TagService;
using BlogProject.Business.Services.UserService;
using BlogProject.DataAccess.Data;
using BlogProject.DataAccess.Repositories.Base;
using BlogProject.DataAccess.Repositories.Base.Interfaces;
using BlogProject.DataAccess.Repositories.Relations;
using BlogProject.DataAccess.Repositories.Relations.Interfaces;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
var builder = WebApplication.CreateBuilder(args);
var isDevelopment = builder.Environment.IsDevelopment();
builder.Services.AddControllers();
builder.Services.AddCors();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var key = builder.Configuration["JsonWebTokenKeys:IssuerSigningKey"];
var encodedKey = Encoding.UTF8.GetBytes(key);
var signingKey = new SymmetricSecurityKey(encodedKey);
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = false,
ValidateAudience = false,
};
});
builder.Services.AddScoped<IJwtAuthenticationManager, JwtAuthenticationManager>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
var openApiSecurityScheme = new OpenApiSecurityScheme
{
Description = "Standard Authorization header using the Bearer scheme (\"bearer {token}\")",
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
};
options.AddSecurityDefinition("oauth2", openApiSecurityScheme);
options.OperationFilter<SecurityRequirementsOperationFilter>();
});
builder.Services.AddAutoMapper(typeof(MapProfile));
builder.Services.AddDbContext<BlogProjectDbContext>(
optionsBuilder =>
{
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
optionsBuilder.UseNpgsql(connectionString);
optionsBuilder.EnableDetailedErrors(isDevelopment);
optionsBuilder.EnableSensitiveDataLogging(isDevelopment);
});
builder.Services.AddScoped<IPostRepository, EFPostRepository>();
builder.Services.AddScoped<ICommentRepository, EFCommentRepository>();
builder.Services.AddScoped<IUserRepository, EFUserRepository>();
builder.Services.AddScoped<ITagRepository, EFTagRepository>();
builder.Services.AddScoped<ICategoryRepository, EFCategoryRepository>();
builder.Services.AddScoped<IPostsEditorsRepository, EFPostsEditorsRepository>();
builder.Services.AddScoped<IPostsTagsRepository, EFPostsTagsRepository>();
builder.Services.AddScoped<IUsersCommentReactionsRepository, EFUsersCommentReactionsRepository>();
builder.Services.AddScoped<IUsersPostReactionsRepository, EFUsersPostReactionsRepository>();
builder.Services.AddScoped<IPostService, PostService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ICommentService, CommentService>();
builder.Services.AddScoped<ITagService, TagService>();
builder.Services.AddScoped<ITagService, TagService>();
var app = builder.Build();
if (isDevelopment)
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors(policyBuilder => policyBuilder.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000"));
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Business/Services/AuthenticationService/JwtAuthenticationManager.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using BlogProject.DataAccess.Repositories.Base.Interfaces;
using BlogProject.Entities.Base;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames;
namespace BlogProject.Business.Services.AuthenticationService;
public class JwtAuthenticationManager : IJwtAuthenticationManager
{
private readonly IUserRepository _userRepository;
private readonly string _jwtTokenSecret;
private readonly string _jwtTokenSubject;
public JwtAuthenticationManager(
IConfiguration configuration,
IUserRepository userRepository)
{
_jwtTokenSecret = configuration["JsonWebTokenKeys:IssuerSigningKey"];
_jwtTokenSubject = configuration["JsonWebTokenKeys:Subject"];
_userRepository = userRepository;
}
public async Task<string?> GetJwtTokenAsync(string username)
{
var user = await _userRepository.ValidateUserAsync(username);
if(user == null) return null;
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtTokenSecret));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var expireTime = DateTime.UtcNow.AddDays(1);
var token = new JwtSecurityToken(
claims : GetClaim(user),
expires : new DateTimeOffset(expireTime).DateTime,
signingCredentials : credentials);
var tokenHandler = new JwtSecurityTokenHandler();
var jwtString = tokenHandler.WriteToken(token);
return jwtString;
}
private IEnumerable<Claim> GetClaim(User user)
{
return new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, _jwtTokenSubject),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
new Claim("Id", user.Id.ToString()),
new Claim("UserName", user.Username),
new Claim("Email", user.Email),
new Claim("Role", user.Role)
};
}
}
API/Controller/UserController.cs : Login
[HttpGet("Login")]
public async Task<IActionResult> Login(string username, string password)
{
var response = await _userService.ValidateUserAsync(username, password);
if (response == null) return NotFound();
var tokenResponse = await _jwtAuthenticationManager.GetJwtTokenAsync(response.UserName);
if (tokenResponse == null) throw new Exception("Token is null");
response.Token = tokenResponse;
Ok(response);
}
CodePudding user response:
This is very embarrasing. Recently I deleted some of the packages from API. Looks like deleting "System.IdentityModel.Tokens.Jwt" somehow breaks the code. But there is something I don't understand. It still says "invalid signature" at jwt.io but the token works.
And Yes I pasted the secret to the field.