DotNet 7 JSON Web Token

DotNet 7 JSON Web Token
Photo by Markus Spiske / Unsplash

Building Web Apps with .Net 7: A Comprehensive Guide to JSON Web Tokens

Recently, my colleague Michel and I embarked on a journey to construct a web application using C# with .Net 7. What initially seemed like a routine task became an exciting adventure, as .Net 7 presented a new landscape compared to .Net 3.5.

Setting Up the Environment

Regardless of our individual IDE preferences - JetBrains Ridder for me and Visual Studio for Michel - we created a new solution to tackle this project head-on. Our experience in varied programming languages such as Java, C#, Elm, TypeScript, Kotlin, and Elixir equipped us to tackle this new challenge.

Our plan? To separate the authentication API from the business API. To kick things off, we added a new ASP.NET Core web API project at the root of our solution using the command dotnet new webapi.

Understanding .Net 7 Authentication

We soon discovered an intriguing change in .Net 7: there was no option for Individual Authentication without Azure. It was a reminder of the ever-evolving nature of .Net, and Microsoft’s clever strategies to retain their customers.

Determined, we decided to devise our own solution for authentication.

Creating a JWT in .Net 7

Building Domain Objects

The first step is to create a new web API project without authentication using the command:

dotnet new webapi -au None -n "SoCraDev.Lab.RapidScrum.Authentification"

Next, we build the model objects within a “domains” folder at the root of the project, including the User class that serves as our domain object and a UserRequest class to separate the DTO from the request and response.

namespace SoCraDev.Lab.RapidScrum.Token.Domain;

public class User
{
    public string UserName { get; set; } = string.Empty;
    public string PasswordHash { get; set; }
}
public class UserRequest
{
    public required string UserName { get; set; }
    public required string Password { get; set; }
}

Creating the Authentication Controller

We then establish the Authentication controller, where users can authenticate and obtain a token. This process requires adding libraries from NuGet, namely BCrypt.Net, which aids in string encryption.

In the AuthController, we hash the password using BCrypt and provide methods to register a user and verify login credentials.

[Route("api/[controller]")]
[ApiController]
public class AuthController : Controller
{
   private readonly IConfiguration _configuration;
   private static User _user = new();

   public AuthController(IConfiguration configuration)
   {
      _configuration = configuration;
   }
    
    [HttpPost("Register")]
   public ActionResult<User> Register(UserRequest userRequest)
   {
      string passwordHash = BCrypt.Net.BCrypt.HashPassword(userRequest.Password);
      _user.UserName = userRequest.UserName;
      _user.PasswordHash = passwordHash;
      
      return Ok(_user);
      
   }
   
   [HttpPost("login")]
   public ActionResult<User> Login(UserRequest userRequest)
   {
      if(_user.UserName != userRequest.UserName)
      {
         return Unauthorized();
      }
      if (!BCrypt.Net.BCrypt.Verify(userRequest.Password, _user.PasswordHash))
      {
         return Unauthorized();   
      }
      return _user;
   }

Generating JWT Tokens

The next step involves creating a method to generate authentication tokens. For this, we add libraries - Microsoft.IdentityModel.Tokens and System.IdentityModel.Tokens.Jwt - and a token key in the appsettings.json file.

"AppSettings": {
    "Token": "SuperSecretTokenSuperSecretTokenSuperSecretTokenSuperSecretToken"
  }

We create a CreateToken method within the AuthController that constructs and returns a JWT.

private readonly IConfiguration _configuration;

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

private string CreateToken(User user)
   {
      List<Claim> claims = new()
      {
         new Claim(ClaimTypes.Name, user.UserName)
      };
      
      var key = new SymmetricSecurityKey(
         Encoding.UTF8.GetBytes(
            _configuration
                .GetSection("AppSettings:Token")
                .Value!));
      
      var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
      
      var token = new JwtSecurityToken(
         issuer: "localhost",
         audience: "localhost",
         claims: claims,
         expires: DateTime.Now.AddDays(1),
         signingCredentials: credentials);
      
      var jwt = new JwtSecurityTokenHandler().WriteToken(token);

      return jwt;
   }

We call the CreateToken method inside our Register method

    [HttpPost("Register")]
   public ActionResult<User> Register(UserRequest userRequest)
   {
      string passwordHash = BCrypt.Net.BCrypt.HashPassword(userRequest.Password);
      _user.UserName = userRequest.UserName;
      _user.PasswordHash = passwordHash;
      
      string token = CreateToken(_user);
      return Ok(token);
      
   }

Running the API application now yields a 512-byte token.

If you paste your token on https://jwt.io, you will see the domain and the username.

And there you have it! A step-by-step guide to handling JSON Web Tokens in .Net 7.

Building Web Apps with
In our previous post-.Net 7 & JWT, we explained how to create a JSON Web Token. This article explores authorization via web tokens in .Net 7. It would be best if you were authenticated to access this Controller…
Alexandre Cuva

Alexandre Cuva

Nyon, Switzerland