Asp.Net Core Securing Apis With Jwt Complete Guide

 Last Update:2025-06-23T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    8 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of ASP.NET Core Securing APIs with JWT

Securing APIs with JWT in ASP.NET Core: A Comprehensive Guide

Understanding JWT

Before diving into the implementation, it's crucial to understand what JWT entails.

Structure of a JWT

  • Header: Typically encodes the algorithm type (e.g., HMAC SHA256 or RSA) and token type, which is JWT.
  • Payload: Contains the claims; this section can encode user information and role, and it is also JSON-encoded.
  • Signature: The signature is created by taking the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

JWT is often used for authorization and information exchange between the client and the server.

Setting Up JWT Authentication in ASP.NET Core

  1. Install Necessary Packages Ensure you have the Microsoft.AspNetCore.Authentication.JwtBearer package installed. You can add this via NuGet package manager or the command line:

    dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
    
  2. Configure JWT Authentication In the Startup.cs file, configure the JWT authentication service and the middleware. Here's a complete example:

    public class Startup
    {
        public IConfiguration Configuration { get; }
    
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
    
            var key = Encoding.ASCII.GetBytes(Configuration["Jwt:Key"]);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
    
            app.UseRouting();
    
            app.UseAuthentication();
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
    
  3. Generate JWT Token Typically, a token is generated in response to a login request. Here’s a simple example of a Login method in a UsersController.

    [ApiController]
    [Route("api/[controller]")]
    public class UsersController : ControllerBase
    {
        private readonly IConfiguration _configuration;
    
        public UsersController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
    
        [HttpPost("login")]
        public IActionResult Login([FromBody] UserLogin userLogin)
        {
            // Validate username and password
            if (userLogin.Username == "admin" && userLogin.Password == "admin")
            {
                var token = GenerateJwtToken(userLogin.Username);
                return Ok(new { Token = token });
            }
    
            return Unauthorized();
        }
    
        private string GenerateJwtToken(string username)
        {
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
    
            var claims = new[] {
                new Claim(JwtRegisteredClaimNames.Sub, username),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            };
    
            var token = new JwtSecurityToken(
                issuer: _configuration["Jwt:Issuer"],
                audience: _configuration["Jwt:Audience"],
                claims: claims,
                expires: DateTime.Now.AddMinutes(30),
                signingCredentials: credentials);
    
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
    

    Configuration Don't forget to add the JWT settings to your appsettings.json:

    {
      "Jwt": {
        "Key": "your_secret_key_here",
        "Issuer": "your_domain.com",
        "Audience": "your_domain.com"
      }
    }
    
  4. Protected Routes Once JWT is configured, you can protect your API endpoints by decorating them with [Authorize].

    [ApiController]
    [Route("api/[controller]")]
    public class SecureController : ControllerBase
    {
        [HttpGet]
        [Authorize]
        public String Get()
        {
            return "Secure data";
        }
    }
    

Important Considerations

  • Secret Management: Never hard-code your secret keys in the source code; use environment variables or secret management tools.
  • Token Expiry and Refresh: Re-evaluate token expiry policies and implement token refresh mechanisms for better security.
  • Secure Headers: Leverage security headers to mitigate certain attack vectors.
  • HTTPS: Always use HTTPS to ensure that the tokens are transmitted securely.

By following these guidelines, you will be able to secure your ASP.NET Core APIs using JWT, thereby ensuring smooth and secure user experiences.

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement ASP.NET Core Securing APIs with JWT

Complete Examples, Step by Step for Beginners: Securing APIs with JWT in ASP.NET Core

Prerequisites

  • Basic understanding of ASP.NET Core
  • Visual Studio (or any code editor)
  • .NET Core SDK

Step-by-Step Guide

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

  1. Open Visual Studio.
  2. Select "Create a new project".
  3. Choose "ASP.NET Core Web API".
  4. Name your project and click "Create".
  5. In the template options, ensure you are selecting the latest version of .NET Core or .NET 5/6/7, and click "Create".

Step 2: Install Required Packages

For JWT Authentication, we don't usually need to install any additional packages as it's supported by the ASP.NET Core Identity framework via the built-in middleware.

However, if you want to use Microsoft.AspNetCore.Authentication.JwtBearer, you do need to install it via NuGet Package Manager:

  • Open the NuGet Package Manager Console
  • Install the following package using the command:
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

Step 3: Create Models

We need to create models for user authentication.

UserModel.cs

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

TokenModel.cs

public class TokenModel
{
    public string Token { get; set; }
    public DateTime Expiration { get; set; }
}

Step 4: Set up JWT Authentication in Startup.cs or Program.cs (for .NET 6+)

If you're using .NET 6 or newer, configure your services in Program.cs:

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

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
    });

builder.Services.AddAuthorization();

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

var app = builder.Build();

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

app.UseHttpsRedirection();

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

app.MapControllers();

app.Run();

Step 5: Add JWT Configuration to appsettings.json

Add these settings in your appsettings.json file:

{
  "Jwt": {
    "Key": "your_secret_key_here",
    "Issuer": "your_issuer_here",
    "Audience": "your_audience_here"
  }
}

Make sure to replace "your_secret_key_here", "your_issuer_here", and "your_audience_here" with your actual values.

Step 6: Controller Implementation

Create a controller to handle authentication and provide JWT tokens.

AuthController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController]
[Route("[controller]")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] UserModel user)
    {
        // Normally you would check the user credentials against a database
        if (user.Username != "admin" || user.Password != "password")
        {
            return Unauthorized("Invalid username or password");
        }

        var token = GenerateJwtToken(user);
        return Ok(new TokenModel { Token = token, Expiration = DateTime.Now.AddHours(1) });
    }

    private string GenerateJwtToken(UserModel user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.Name, user.Username)
        };

        var token = new JwtSecurityToken(
            issuer: _configuration["Jwt:Issuer"],
            audience: _configuration["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddHours(1),
            signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Step 7: Secure Your API

You now need to secure your API endpoints by adding the [Authorize] attribute. For example, let's secure a simple WeatherForecast endpoint:

WeatherForecastController.cs

[ApiController]
[Route("[controller]")]
[Authorize] // Securing all actions
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }

    public class WeatherForecast
    {
        public DateTime Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string? Summary { get; set; }
    }
}

Testing the API

  • Use a tool like Postman to send requests to your /login endpoint with a valid username and password to receive a token.
  • Include the JWT in the Authorization header as a Bearer token when making requests to the secured endpoints.

Summary

In this tutorial, we've gone through the process of securing ASP.NET Core Web APIs with JWT Authentication from scratch. You now understand how to create a project, configure JWT settings, set up authentication, and protect your API endpoints using the [Authorize] attribute.

Top 10 Interview Questions & Answers on ASP.NET Core Securing APIs with JWT

1. What is JSON Web Token (JWT)?

Answer:
JWT, or JSON Web Token, is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.

2. Why should I use JWT to secure my ASP.NET Core APIs?

Answer:
JWT offers several advantages for securing APIs:

  • Stateless Authentication: No need to store session information on the server.
  • Cross-Domain / CORS: JWTs are particularly useful for Single Sign-On (SSO) across different domains.
  • Efficiency: Easy to pass around within HTTP headers and small enough (compact), making it suitable for mobile apps.
  • Security: Data integrity and authenticity are ensured by the digital signature.

3. How do I generate a JWT in ASP.NET Core?

Answer:
To generate a JWT in ASP.NET Core, you can use the System.IdentityModel.Tokens.Jwt NuGet package. A basic example involves creating a security token using user claims and signing it with a cryptographic key:

var claims = new[]
{
    new Claim(ClaimTypes.NameIdentifier, user.Id),
    new Claim(ClaimTypes.Name, user.UserName)
};

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

var token = new JwtSecurityToken(
    issuer: "Issuer",
    audience: "Audience",
    claims: claims,
    expires: DateTime.Now.AddDays(1),
    signingCredentials: creds);

var jwt = new JwtSecurityTokenHandler().WriteToken(token);

4. How can I validate JWTs in ASP.NET Core?

Answer:
To validate JWTs, configure JWT Bearer authentication in your Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    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 = "Issuer",
            ValidAudience = "Audience",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("YOUR_SECRET_KEY_HERE"))
        };
    });

    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Use Authentication middleware
    app.UseAuthentication();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

5. Where should I store keys used for signing JWTs?

Answer:
For production environments, avoid hardcoding keys directly in your codebase. Store sensitive information like keys in environment variables, Azure Key Vault, or a secure configuration management system to protect them from unauthorized access.

6. How do I expire and refresh JWTs in ASP.NET Core?

Answer:

  • Expiration: Set the expiration time using expires when creating the JWT. The example in Q3 sets the token to expire in one day.
  • Refresh Token: Implement a mechanism where expired tokens can be refreshed by issuing a new token after validating a refresh token. Store refresh tokens securely, often in a database.

Here’s a simplified example for setting expiration:

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(claims),
    Expires = DateTime.UtcNow.AddDays(1), // Expiry time
    SigningCredentials = creds // Signing key and algorithm
};

7. Can I add custom claims to JWT in ASP.NET Core?

Answer:
Yes, you can add custom claims to JWTs:

var claims = new[]
{
    new Claim(ClaimTypes.NameIdentifier, userId),
    new Claim(ClaimTypes.Email, email),
    new Claim("CustomClaim", "CustomValue")
};

Access these claims later in your application using:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class SampleController : ControllerBase
{
    [HttpGet("Claims")]
    public IActionResult GetClaims()
    {
        var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
        var email = HttpContext.User.FindFirstValue(ClaimTypes.Email);
        var customClaim = HttpContext.User.FindFirstValue("CustomClaim");

        return Ok(new { userId, email, customClaim });
    }
}

8. What security issues should I be aware of when using JWTs?

Answer:
Key security concerns with JWTs include:

  • Secret Key Management: Ensure that the secret key is never stored in plain text and protected.
  • Token Theft: Protect tokens from being stolen through HTTPS and secure client storage mechanisms.
  • Token Lifetime: Keep the token lifetime short to minimize misuse.
  • Revocation: JWT does not have a built-in revocation mechanism. Use refresh tokens or include a unique jti claim that can be marked as issued or revoked.

9. How can I enforce HTTPS when using JWTs in ASP.NET Core?

Answer:
Enforce HTTPS by configuring HTTPS in the ASP.NET Core pipeline (Startup.cs):

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpsRedirection(options =>
    {
        options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
        options.HttpsPort = 5001; // HTTPS port
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection(); // Enforce HTTPS

    app.UseRouting();

    app.UseAuthentication(); // JWT Authentication middleware

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

10. How do I implement role-based access control (RBAC) with JWTs in ASP.NET Core?

Answer:
Include roles as claims in the JWT and utilize [Authorize(Roles)] attribute in controllers/actions:

Generate JWT with role claims:

var claims = new[]
{
    new Claim(ClaimTypes.Name, user.UserName),
    new Claim(ClaimTypes.Role, "Admin") // Add role claim
};

Apply RBAC in controllers:

[Authorize(Roles = "Admin")]
[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> GetAdminDataAsync()
    {
        // Logic here
        return Ok("Admin data");
    }
}

Ensure the role is validated during the JWT validation process. If roles are stored in a dedicated claim, ensure it’s recognized correctly in TokenValidationParameters.

Conclusion

You May Like This Related .NET Topic

Login to post a comment.