Web API  

Implementing JWT-Based Authentication and Role-Based Authorization in .NET Core

In modern web applications, security is critical—especially when dealing with user data, financial transactions, or any form of sensitive operations. JSON Web Tokens (JWT) provide a stateless and scalable solution for authentication, while role-based authorization ensures users can only access what they're permitted to.

In this article, we’ll walk through how to implement JWT-based authentication and role-based authorization in an ASP.NET Core Web API.

🔧 Prerequisites

Before we begin, make sure you have:

  • Basic knowledge of ASP.NET Core and C#

🛠 Step 1. Create a New ASP.NET Core Web API Project

dotnet new webapi -n JwtAuthDemo
cd JwtAuthDemo

📦 Step 2. Install Required NuGet Packages

Install the following NuGet package for JWT support:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

🧩 Step 3. Configure JWT Authentication in Program.cs

Add the following JWT configuration to Program.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Add Authentication services
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = "your-app",
        ValidAudience = "your-app",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSuperSecretKey123"))
    };
});

// Add Authorization
builder.Services.AddAuthorization();

builder.Services.AddControllers();
var app = builder.Build();

app.UseAuthentication(); // Must come before UseAuthorization
app.UseAuthorization();

app.MapControllers();
app.Run();

🛡 Replace "YourSuperSecretKey123" with a secure key and store it in a secure place, such as Azure Key Vault or environment variables.

🔐 Step 4. Generate JWT Tokens

Create a service or endpoint to generate JWT tokens. Example:

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginModel login)
    {
        if (login.Username == "admin" && login.Password == "password") // Replace with real validation
        {
            var claims = new[]
            {
                new Claim(ClaimTypes.Name, login.Username),
                new Claim(ClaimTypes.Role, "Admin")
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSuperSecretKey123"));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: "your-app",
                audience: "your-app",
                claims: claims,
                expires: DateTime.Now.AddHours(1),
                signingCredentials: creds);

            return Ok(new
            {
                token = new JwtSecurityTokenHandler().WriteToken(token)
            });
        }

        return Unauthorized();
    }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

🧾 Step 5. Secure Your Endpoints with Role-Based Authorization

In your controller, protect routes using the [Authorize] attribute and specify roles:

[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase
{
    [HttpGet("dashboard")]
    [Authorize(Roles = "Admin")]
    public IActionResult GetDashboard()
    {
        return Ok("Welcome to the admin dashboard!");
    }
}

✅ Step 6. Test Your API

  1. POST to /api/auth/login with valid credentials

    {
      "username": "admin",
      "password": "password"
    }
    
  2. Receive a JWT token in response.

  3. Include the token in the Authorization header:

Authorization: Bearer {your-token}

Access protected routes like /api/admin/dashboard.

🔒 Best Practices

  • Never hardcode secrets: use environment variables or secret managers.

  • Set token expiration: always use short-lived tokens.

  • Use HTTPS: always encrypt traffic.

  • Use Refresh Tokens: for long-lived sessions.

  • Validate claims: especially roles and permissions.

  • Log authentication failures: for monitoring and alerting.

🧠 Conclusion

JWT-based authentication with role-based authorization offers a flexible and scalable way to secure your ASP.NET Core Web APIs. Whether you're building an internal API or a public-facing application, this architecture keeps your endpoints secure and your users' data protected.

Let me know if you'd like to extend this with refresh tokens, custom claims, policy-based authorization, or integration with Identity Server / ASP.NET Core Identity.