I have created minimal ASP.NET Core application which is meant to experiment with JWT tokens.
I have created services to generate the JWT tokens and also implemented auth requiring those tokens.
Here's my startup Program.cs:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using netwebapi;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
// Authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = builder.Configuration["JWT:ValidAudience"],
ValidIssuer = builder.Configuration["JWT:ValidIssuer"],
ClockSkew = TimeSpan.Zero,
ValidateLifetime = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"]))
};
});
builder.Services.AddAuthorization();
builder.Services.AddTransient();
builder.Services.AddTransient();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Code generating tokens:
public class TokenService : ITokenService
{
private readonly IConfiguration _configuration;
public TokenService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GenerateAccessToken(IEnumerable claims)
{
var tokenHandler = new JwtSecurityTokenHandler();
// Create a symmetric security key using the secret key from the configuration.
var authSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = _configuration["JWT:ValidIssuer"],
Audience = _configuration["JWT:ValidAudience"],
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddMinutes(15),
SigningCredentials = new SigningCredentials
(authSigningKey, SecurityAlgorithms.HmacSha256)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
Now, in the endpoint I can get valid tokens, which I confirm using jwt.io. It has valid issues, audience and also valid signature.
Then I add Authorize to one of my endpoints, and add this header when calling it:
Authorization: Bearer ...token...
I get a response http 401 (unauthorized).
Of course, if I remove the Authorize data annotation, everything works.
So why is it not working?
Settings are there, token seems to be valid (as confirmed at jwt.io), yet, I am still unable to make authorized request.
Of course, for simplicity, I used issuer and audience set to the base URL of the app running on localhost. Here's part of my settings:
"JWT": {
"ValidAudience": "http://localhost:5235",
"ValidIssuer": "http://localhost:5235",
"Secret": "super secret"
}