How to add JWT Token Authorisation to a NET Core Web API

Step-by-step guide


Step 1: * Install Necessary NuGet Packages

First, ensure that you have the following NuGet packages installed in your project:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

We will assume that this is a Web app calling a Web API

In program.cs we will need to add the HttpClient to the services collection to converse with the API, the HttpClient is now available for dependency injection.

...

builder.Services.AddHttpClient();  // Registers HttpClient

var app = builder.Build();

Step 1: Create the Login view

Under the Home controller (change as required) add the Login.cshtml page

@using Site.Models

@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@

@model LoginDto
@{
    ViewData["Title"] = "Login";
}

<form asp-action="Login" method="post" class="mt-5 w-30 mx-auto p-4 shadow rounded">
    <h3 class="text-center mb-4">Login</h3>

    <div class="mb-3">
        <label asp-for="Username" class="form-label">Username</label>
        <input asp-for="Username" type="text" class="form-control" placeholder="Enter your username" required />
        <span asp-validation-for="Username" class="text-danger"></span>
    </div>

    <div class="mb-3">
        <label asp-for="Password" class="form-label">Password</label>
        <input asp-for="Password" class="form-control" placeholder="Enter your password" required />
        <span asp-validation-for="Password" class="text-danger"></span>
    </div>

    <div class="d-grid gap-2">
        <button type="submit" class="btn btn-primary btn-block">Login</button>
    </div>
</form>

Step 3: Call Login()
if we are using an MVC controller this would require a Get (initiated by the link above) and a Post method initiated by the Login.cshtml (above) form POST

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly HttpClient _httpClient;

    public HomeController(ILogger<HomeController> logger, HttpClient httpClient)
    {
        _logger = logger;
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri("http://localhost:5111/api/"); // Replace with your API's base URL
    }
....
....

[HttpGet]
public IActionResult Login()
{
   return View(new LoginDto()); // Show the empty form
}

[HttpPost]
public async Task<IActionResult> Login(LoginDto loginDto)
{
   if (!ModelState.IsValid)
   {
       return View(loginDto); // Return the form with validation errors
   }

   // Send the login DTO to the API using a POST request
   var response = await _httpClient.PostAsJsonAsync("contacts/login", loginDto);

   if (response.IsSuccessStatusCode)
   {
       // Read the response body as NewUserDto
       var newUser = await response.Content.ReadFromJsonAsync<NewUserDto>();

       // Example: store token in TempData or Session
       TempData["Token"] = newUser.Token;

       //You can verify the token at JWT.IO
       string cookiename = "MyAPIAccess";
       string tokenValue = newUser.Token;
       Response.Cookies.Append(
           cookiename,
           tokenValue,
           new CookieOptions
           {
               HttpOnly = true,
               SameSite = SameSiteMode.Strict
           });

       // Redirect to Home page or another view after successful login
       return RedirectToAction("Index", "Home");
   }

   // If login fails, display an error message and return the view
   ModelState.AddModelError("", "Invalid login attempt. Please try again.");
   return View(loginDto);
}