---
# System prepended metadata

title: Week 08/09 - Authentication & Authorization
tags: [Restful API, ASP.NET CORE, Back-end, Titanium, Security]

---

###### tags: `Back-end`,`Restful API`,`ASP.NET CORE`,`Titanium`,`Security`
# Week 08/09 - Authentication & Authorization
## Introduction
This session will cover the essentials of JWT (JSON Web Tokens) for authentication in a .NET Core 8 RESTful API, Will use EF Identity package, diving into how JWT works, its structure, best practices, and how to implement it with middleware and role-based route protection.

Authentication is the process of verifying who a user is. In a RESTful API, protecting endpoints ensures only authorized users can access certain data or perform specific actions.

## Identity EF Package and Its Role
ASP.NET Core Identity provides the tools to handle authentication and authorization. The Identity framework, when combined with Entity Framework Core (EF Core), offers built-in database support for managing user data.
Supports secure password storage, user management, roles, and claims-based authentication.

##  Installing and Setting Up ASP.NET Core Identity
### Install the required NuGet packages:
`dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
`
### Configure services in Program.cs:
```csharp!
builder.Services.AddDbContext<MainAppContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<User, IdentityRole<int>>()
    .AddEntityFrameworkStores<MainAppContext>()
    .AddDefaultTokenProviders();

```

### Extending IdentityUser with Integer Primary Key
```csharp!
public class ApplicationUser : IdentityUser<int> 
{
    // Additional custom properties can go here
}

```
### Update ApplicationDbContext to use IdentityDbContext:
```csharp!
public class MainAppContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
    public MainAppContext(DbContextOptions<MainAppContext> options)
        : base(options) { }
}

```

### Database Migration and Update
Use the following commands to apply migrations and update the database:
```
dotnet ef migrations add IdentityMig
dotnet ef database update
OR
Add-Migration  IdentityMig
Update-Database
```

## Implementing an Authentication Controller (AuthController)
The AuthController will include a Login endpoint to authenticate users by checking their credentials.

```csharp!
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly JwtService _jwtService;

    public AuthController(UserManager<ApplicationUser> userManager, JwtService jwtService)
    {
        _userManager = userManager;
        _jwtService = jwtService;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] AuthRequest model)
    {
        var user = await _userManager.FindByNameAsync(model.Username);
        if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
        {
            var role = (await _userManager.GetRolesAsync(user)).FirstOrDefault();
            var token = _jwtService.GenerateJWT(user, role);
            return Ok(new { Token = token });
        }
        return Unauthorized();
    }
}

```
DTO for Login:
```csharp!
public class AuthRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

```
## JWT
JWT is a secure, compact token format that’s commonly used to manage authentication between a client and server. Once a user logs in, the server generates a JWT that’s sent to the client. This token, which is self-contained and includes claims about the user (like roles and permissions), enables the client to make authenticated requests without re-authenticating.

### JWT Structure
A JWT has three main parts:

* Header: Defines the token type and the signing algorithm (e.g., HS256).
* Payload: Contains claims (statements about the user, such as username, roles, exp for expiry, etc.).
* Signature: Ensures the token's integrity by signing the encoded header and payload with a secret key.

The format of a JWT is:
`{Header}.{Payload}.{Signature}`
### Install JwtBearer for JWT implementation
Install JwtBearer package from Nuget Manager.

### Setup JWT
In ConfigureServices, add authentication and configure JWT bearer settings. Make sure to inject UserManager and SignInManager for user authentication.

```csharp
public void ConfigureServices(IServiceCollection services)
{
    // Add Identity and configure it
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    // JWT Authentication configuration
    var jwtSettings = Configuration.GetSection("Jwt");
    var key = Encoding.UTF8.GetBytes(jwtSettings["Key"]);

    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)
        };
    });

    services.AddControllers();
}

```

Jwt options setup:
```csharp
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "yourapi.com",
            ValidAudience = "yourapi.com",
            IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("YourSecretKey"))
        };
    });
```

### Implementing JwtService
```csharp
public class JwtService
{
    private readonly IConfiguration _config;

    public JwtService(IConfiguration config)
    {
        _config = config;
    }

    public string GenerateJWT(ApplicationUser user, string role)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(ClaimTypes.Role, role)
            },
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_config["Jwt:ExpireInMinutes"])),
            signingCredentials: creds);

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

```

Register JwtService in Program.cs:

```jsonld
"Jwt": {
    "Key": "asdkjkejr##$@daslkw[efkf]fadirai",
    "Issuer": "Titanium",
    "Audience": "Trainers.Trainees",
    "ExpireInMinutes": 30
}

```

###  Testing the Login Endpoint
Use Postman or a similar tool to send a POST request to /api/auth/login with the correct username and password. If successful, a JWT token will be returned in the response.


### Enable Jwt Middleware to protect the endpoints
Middleware for extracting and validating Jwt Token
```csharp!
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    // Add Authentication and Authorization middleware
    app.UseAuthentication();
    app.UseAuthorization();

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

```

### Using [Authorize] Attribute to Protect Endpoints
Apply [Authorize] on controllers or actions to restrict access to authenticated users:
```csharp
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ProgramsController : ControllerBase
{
    // Only accessible to authenticated users
}

```



Checking controller:
```csharp=
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class SampleController : ControllerBase
{
    [HttpGet]
    public IActionResult GetSecureData()
    {
        return Ok("This is a secure endpoint");
    }
}

```

You can specify roles if you need role-based authorization:

```csharp!
[Authorize(Roles = "Admin")]
public class AdminController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAdminData()
    {
        return Ok("This is an Admin-only endpoint");
    }
}

```
## Implementing Role-Based Access Control
```csharp
[ApiController]
[Route("api/[controller]")]
public class RolesController : ControllerBase
{
    private readonly RoleManager<ApplicationRole> _roleManager;

    public RolesController(RoleManager<ApplicationRole> roleManager)
    {
        _roleManager = roleManager;
    }

    [HttpPost("create")]
    public async Task<IActionResult> CreateRole([FromBody] string roleName)
    {
        var result = await _roleManager.CreateAsync(new ApplicationRole { Name = roleName });
        return result.Succeeded ? Ok() : BadRequest(result.Errors);
    }

    [HttpGet("getAll")]
    public IActionResult GetAllRoles()
    {
        var roles = _roleManager.Roles.ToList();
        return Ok(roles);
    }
}

```

UsersController to Assign Roles:

```csharp
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _userManager;

    public UsersController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    [HttpPost("assignRole")]
    public async Task<IActionResult> AssignRole(string userName, string roleName)
    {
        var user = await _userManager.FindByNameAsync(userName);
        if (user == null) return NotFound();
        var result = await _userManager.AddToRoleAsync(user, roleName);
        return result.Succeeded ? Ok() : BadRequest(result.Errors);
    }
}

```

