DEV Community

mohamed Tayel
mohamed Tayel

Posted on • Updated on

Exploring Identity API Endpoints in .NET 8: Implementing and Testing JWT Authentication

.NET 8 introduces new Identity API Endpoints to simplify user authentication and authorization. In this article, we'll explore how to implement JWT authentication using these endpoints and demonstrate how to test your setup effectively. You can find the complete source code for this article on

https://github.com/mohamedtayel1980/DotNet8NewFeature/tree/main/DotNet8NewFeature/IdentityApiSample.

Table of Contents

  1. Introduction to Identity API Endpoints
  2. Setting Up Your ASP.NET Core Project
  3. Configuring Identity and JWT Authentication
  4. Implementing the Identity API Endpoints
  5. Generating and Using JWT Tokens
  6. Testing Your Endpoints
  7. Conclusion

1. Introduction to Identity API Endpoints

The new Identity API Endpoints in .NET 8 provide a streamlined approach to managing user authentication and authorization. These endpoints cover common identity operations such as user registration, login, and password management, reducing boilerplate code and simplifying configuration.

2. Setting Up Your ASP.NET Core Project

  1. Create a new ASP.NET Core project:
   dotnet new webapi -n IdentityApiSample
   cd IdentityApiSample
Enter fullscreen mode Exit fullscreen mode
  1. Add the necessary NuGet packages:
   dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
   dotnet add package Microsoft.EntityFrameworkCore.SqlServer
   dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
   dotnet add package Swashbuckle.AspNetCore
Enter fullscreen mode Exit fullscreen mode

3. Configuring Identity and JWT Authentication

Update your appsettings.json with the JWT settings:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.\\MSSQLSERVER01;Database=IdentitySample;Trusted_Connection=True;Encrypt=False;"
  },
  "Jwt": {
    "Key": "YourVeryLongSecretKeyHere1234567890",  // At least 32 characters long
    "Issuer": "YourIssuer",
    "Audience": "YourAudience"
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Implementing the Identity API Endpoints

Update your Program.cs to configure services and middleware:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Configure Kestrel to listen on specific ports
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenAnyIP(5002); // HTTP port
    serverOptions.ListenAnyIP(5003, listenOptions => listenOptions.UseHttps()); // HTTPS port
});

// Add services to the container.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

var jwtSettings = builder.Configuration.GetSection("Jwt");
var key = Encoding.UTF8.GetBytes(jwtSettings["Key"]);

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 = jwtSettings["Issuer"],
        ValidAudience = jwtSettings["Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(key)
    };
});

builder.Services.AddControllers();

// Add Swagger services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Identity API", Version = "v1" });
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = "Please enter a valid token",
        Name = "Authorization",
        Type = SecuritySchemeType.Http,
        BearerFormat = "JWT",
        Scheme = "Bearer"
    });
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] { }
        }
    });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Identity API V1");
        c.RoutePrefix = string.Empty; // Set Swagger UI at the app's root
    });
}

app.UseHttpsRedirection();

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

app.MapControllers();

app.Run();
Enter fullscreen mode Exit fullscreen mode

Create the ApplicationDbContext class:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

5. Generating and Using JWT Tokens

Create the AccountController to handle registration and login:

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

[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly IConfiguration _configuration;

    public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, IConfiguration configuration)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _configuration = configuration;
    }

    [HttpPost("register")]
    public async Task<IActionResult> Register([FromBody] RegisterModel model)
    {
        var user = new IdentityUser { UserName = model.Username, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            return Ok(new { message = "User registered successfully" });
        }
        return BadRequest(result.Errors);
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginModel model)
    {
        var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, false, false);
        if (result.Succeeded)
        {
            var user = await _userManager.FindByNameAsync(model.Username);
            var token = GenerateJwtToken(user);
            return Ok(new { token });
        }
        return Unauthorized();
    }

    private string GenerateJwtToken(IdentityUser user)
    {
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

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

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

public class RegisterModel
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

6. Testing Your Endpoints

Using Postman

  1. Login to Get the Token:

    • Send a POST request to http://localhost:5002/api/account/login with the username and password to get the token.
    • Copy the token from the response.
  2. Include the Token in the Authorization Header:

    • Open a new request tab.
    • Go to the Headers section.
    • Add a new header with the key Authorization and the value Bearer YOUR_JWT_TOKEN (replace YOUR_JWT_TOKEN with the token you copied).
  3. Send Requests to Secure Endpoints:

    • Send a GET request to http://localhost:5002/api/sample/secure-data to access secure data.

Using Swagger UI

  1. Login to Get the Token:

    • Use the /api/account/login endpoint to get the token.
  2. Authorize with the Token:

    • Click the Authorize button in Swagger UI.
    • Enter Bearer YOUR_JWT_TOKEN (replace YOUR_JWT_TOKEN with the token you copied).
    • Click Authorize.
  3. Access Secure Endpoints:

    • Now you can access secure endpoints directly from Swagger UI.

7. Conclusion

In this article, we've explored the new Identity API Endpoints in .NET 8 and demonstrated how to implement JWT authentication. By following these steps, you can secure your API endpoints and test them effectively using tools like Postman and Swagger UI.

Top comments (0)