In my previous article, I covered validation in Minimal APIs, but security is just as important. Most applications rely on JWT authentication for securing APIs, so in this article, I’ll walk you through how to create an Identity Service for JWT authentication.
👉 Note: This article will not include ASP.NET Core Identity. If you're interested in a separate article on that, let me know, and I’ll add an implementation to my GitHub repo.
📌 Check out the full implementation here:
https://github.com/stevsharp/minimal-vs-controller-benchmark/tree/main/TestJwt
Step 1: Creating the Identity Service
Instead of placing JWT generation logic inside our API endpoints, it's best to encapsulate it inside a service. This makes our authentication system more modular and testable.
🔹 IdentityService.cs
We define a simple IdentityService that handles JWT token generation:
public class IdentityService(JwtConfiguration config)
{
private readonly JwtConfiguration _config = config;
public async Task<string> GenerateToken(string username)
{
await Task.Delay(100); // Simulate a database call
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "123456"), // Example subject ID
new Claim(JwtRegisteredClaimNames.Email, "admin@admin.gr"),
new Claim(JwtRegisteredClaimNames.PreferredUsername, username)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config.Secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config.Issuer,
audience: _config.Audience,
claims: claims,
expires: DateTime.UtcNow.AddDays(_config.ExpireDays),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
🔹 Registering the Service in Program.cs
To make the service available for dependency injection, register it in the DI container:
builder.Services.AddScoped<IdentityService>();
Step 2: Configuring JWT Authentication
Now, we need to configure authentication in Program.cs.
🔹 JWT Configuration Class
Let’s create a class to manage JWT settings in appsettings.json:
public record JwtConfiguration
{
public string Secret { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public int ExpireDays { get; set; } = 7;
}
Load it into the dependency injection container:
var jwtConfig = builder.Configuration.GetSection("JwtSettings").Get<JwtConfiguration>();
builder.Services.AddSingleton(jwtConfig);
** Configure Authentication Middleware**
Add JWT authentication to the application:
public static class JwtAuthBuilderExtensions
{
public static AuthenticationBuilder AddJwtAuthentication(this IServiceCollection services, JwtConfiguration jwtConfiguration)
{
services.AddAuthorization();
return services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtConfiguration.Issuer,
ValidAudience = jwtConfiguration.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfiguration.Secret)),
RequireExpirationTime = true,
};
});
}
}
Enable authentication in the request pipeline:
app.UseAuthentication();
app.UseAuthorization();
Step 3: Implementing Login Endpoint
app.MapPost("/login", async (LoginRequest request, IdentityService identityService, IConfiguration config, ILogger<Program> logger) =>
{
// Retrieve admin credentials from configuration (Optional for flexibility)
var adminUsername = config["Auth:AdminUsername"] ?? "admin";
var adminPassword = config["Auth:AdminPassword"] ?? "password";
// Validate user credentials
if (string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Password))
{
logger.LogWarning("Login failed: Empty username or password.");
return Results.BadRequest(new { message = "Username and password are required." });
}
var userIsAuthenticated = request.Username == adminUsername && request.Password == adminPassword;
if (!userIsAuthenticated)
{
logger.LogWarning("Login failed for user: {Username}", request.Username);
return Results.Unauthorized();
}
// Generate JWT token
var token = await identityService.GenerateToken(request.Username);
logger.LogInformation("User {Username} authenticated successfully.", request.Username);
return Results.Ok(new
{
message = "Login successful",
token
});
})
.AllowAnonymous();
UserLogin Model
public record LoginRequest
{
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
Step 4: Securing API Endpoints
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.RequireAuthorization()
.WithName("GetWeatherForecast")
.WithOpenApi();
Step 5: Testing JWT Authentication
Login: Make a POST /login request with:
json
{
"username": "admin",
"password": "password"
}
You’ll receive a token in response.
Use Token:
Include the token in the Authorization header when making requests:
Authorization: Bearer <your-jwt-token>
Access Protected Routes:
Conclusion
By creating an IdentityService, we’ve modularized JWT authentication, making it easy to maintain and extend. This setup does not include ASP.NET Core Identity, but if you’re interested in that, let me know, and I’ll write a separate article on how to integrate it.
📌 Full code available here:
🔗 TestJwt GitHub Repository
https://github.com/stevsharp/minimal-vs-controller-benchmark/tree/main/TestJwt
Let me know if you have any questions or improvements! 🚀
📌 Useful references
JWT Authentication in ASP.NET Core
🔗 https://learn.microsoft.com/en-us/aspnet/core/security/authentication/jwt
Covers how to configure JWT authentication in ASP.NET Core applications.
Minimal APIs in ASP.NET Core
🔗 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis
Overview of Minimal APIs and how they work in .NET.
Authentication and Authorization in .NET
🔗 https://learn.microsoft.com/en-us/dotnet/core/security/authentication-identity
General authentication and identity management in .NET.
Top comments (0)