Role-Based Authorization in .NET using JWT and LiteDB

Waleed NaveedWaleed Naveed
3 min read

In this post, we’ll walk through building a clean and modular Role-Based Authorization system in a .NET 8 Web API. Using JWT for authentication and LiteDB for storage, we’ll demonstrate how to restrict access to endpoints based on user roles like Admin, Manager, and Employee.

Project Overview

Here’s a high-level summary of what we’ve implemented:

  • JWT Authentication

  • Role-based Authorization at controller and action level

  • Clean Architecture: DTOs, Services, Interfaces, and Repositories

  • NoSQL Storage using LiteDB

  • Seeded roles + users + products on app startup

Folder Structure

Roles We Support

We’ve defined three roles in our app:

public static class RoleConstants
{
    public const string Admin = "Admin";
    public const string Manager = "Manager";
    public const string Employee = "Employee";
}

And grouped them like this:

public static class RolePolicies
{
    public const string Admin = $"{RoleConstants.Admin}";
    public const string AdminOrManager = $"{RoleConstants.Admin},{RoleConstants.Manager}";
    public const string All = $"{RoleConstants.Admin},{RoleConstants.Manager},{RoleConstants.Employee}";
}

JWT Authentication

We’re using JWT bearer tokens for authentication. We have a login endpoint POST /api/auth/login that can be used to login with the seeded admin, manager and employee users:

var admin = new Role { Id = 1, Name = RoleConstants.Admin };
var manager = new Role { Id = 2, Name = RoleConstants.Manager };
var employee = new Role { Id = 3, Name = RoleConstants.Employee };

var adminUser = new User { Id = 1, Username = "admin", Password = "admin123", RoleId = 1 };
var managerUser = new User { Id = 2, Username = "manager", Password = "manager123", RoleId = 2 };
var employeeUser = new User { Id = 3, Username = "employee", Password = "emp123", RoleId = 3 };

If credentials match, we issue a token containing the user's role.
The token must be sent with every protected request via the Authorization header.

(If you're not sure how to enable JWT authentication in Swagger UI, we explained it step-by-step in our earlier blog post:
How to Enable JWT Authentication in Swagger (.NET 8))

Securing the Product Controller

This is the most important piece — let’s restrict access using [Authorize] based on user roles.

[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
    private readonly IProductService _service;

    public ProductController(IProductService service)
    {
        _service = service;
    }

    [HttpGet]
    [Authorize]
    public async Task<IActionResult> GetAll()
    {
        var response = _service.GetAll();
        return Ok(response);
    }

    [HttpGet("{id}")]
    [Authorize]
    public async Task<IActionResult> GetById(int id)
    {
        var response = _service.GetById(id);
        return Ok(response);
    }

    [Authorize(Roles = RolePolicies.AdminOrManager)]
    [HttpPost]
    public async Task<IActionResult> Add([FromBody] AddProductDto dto)
    {
        var response = _service.Add(dto);
        return Ok(response);
    }

    [Authorize(Roles = RolePolicies.AdminOrManager)]
    [HttpPut]
    public async Task<IActionResult> Update([FromBody] UpdateProductDto dto)
    {
        var response = _service.Update(dto);
        return Ok(response);
    }

    [Authorize(Roles = RolePolicies.Admin)]
    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        var response = _service.Delete(id);
        return Ok(response);
    }
}

The real power of [Authorize(Roles = "...")] is fine-grained access control per endpoint.
As per the permissions on the endpoints, every role has the access to GetAll and GetById endpoint. If we login with any user we will be able to see the results:

User with Admin or Manager role can add product:

But user with Employee role cannot add product as this role does not have the rights to access Add endpoint:

Same permissions are there on the Update endpoint as that of Add so only Admin and Manager role users can update product and Employee role users will get 403 error (as in above image) if they try to access Update endpoint.
As per the code, only role which can delete a product is Admin:

Manager and Employee role users will not have access to this endpoint:

Summary

With just a few [Authorize] attributes and some initial seeding logic, we now have a complete Role-Based Authorization system:

  • Admin can perform all actions

  • Manager can add/update products

  • Employee can only view products

GitHub Source Code

Check out the complete project on GitHub.

0
Subscribe to my newsletter

Read articles from Waleed Naveed directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Waleed Naveed
Waleed Naveed