ASP.NET Core - Write a Simple JWT Authentication
Tags: dotnet, csharp, webapi, authentication
Published: 2022-08-31 15:32:02

This is just a simple implementation of JWT authentication to get you started.

1. Add the package `Microsoft.AspNetCore.Authentication.JwtBearer`
2. You need a secret key, store it using `user-secrets`:
    ```sh
    dotnet user-secrets init
    dotnet user-secrets set "Authentication:JwtSecret" "thisismysecret"
    ```
    **Warning!** User secret feature is not intended to be used in production.
3. In your `Program.cs` or `Startup.cs`:    
    ```cs
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc.Authorization;
    using Microsoft.IdentityModel.Tokens;
    using System.Text;
    ```
    Add the service:
    ```cs
    builder.Services
        .AddAuthentication()
        .AddJwtBearer("JwtScheme", options => {
            options.TokenValidationParameters = new TokenValidationParameters 
            {
                ValidIssuer = "https://localhost:<port>",
                ValidAudience = "https://localhost:<port>",
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,                
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Authentication:JwtSecret"])),
            };
    }) 
    ```
    Tell MVC that users should be authenticated and with `JWTScheme`.
    ```cs
    builder.Services.AddControllers(options => {
        options.Filters.Add(new AuthorizeFilter
            (new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .AddAuthenticationSchemes("JwtScheme")
                .Build()));
    })
    ```
    Alternatively, you can use `Authorize` attribute for each controller or endpoint, specifying the scheme(s) to be allowed:
    ```cs 
    [Authorize(AuthenticationSchemes = "JwtScheme")]
    [ApiController]
    [Route("api/[controller]")]
    public class ProductsController : ControllerBase { ... }
    ```
    In the HTTP Request pipeline, add before mapping controllers:
    ```cs
    app.UseAuthentication();
    app.UseAuthorization();
    ```
4. In your authentication controller:
    ```cs
    using Microsoft.IdentityModel.Tokens;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;
    .
    .
    //inject `IConfiguration` to `_configuration` in the constructor.
    ```
    In your login method, add `[AllowAnonymous]` attribute. Then:
    ```cs
    //validate credentials and get user details here
    var key = Encoding.ASCII.GetBytes(_configuration["Authentication:JwtSecret"]);
    var claims = new List<Claim>
        {
            new Claim("sub", user.Id),
            new Claim("name", user.FullName)
        };
    var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Issuer = "https://localhost:<port>",
            Audience = "https://localhost:<port>",
            Expires = DateTime.UtcNow.AddDays(7),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            
        };

    var tokenHandler = new JwtSecurityTokenHandler();
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
    ```
    The login method will return the token generated.
5. In your client's HTTP request, add the `Authorize` header with the value `Bearer <the token generated>`. You can test it via Postman or any testing program you prefer.

**Resource**
[auth0 - Claims](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-claims#registered-claims)
[Infoworld Article - JWT](https://www.infoworld.com/article/3669188/how-to-implement-jwt-authentication-in-aspnet-core-6.html)
[Microsoft Docs - User Secrets](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows)