When you're building an application and want to restrict access to resources and information for different kinds of users, Role-Based Access Control (RBAC) is one of the best, most structured models that you can implement 🔐
What is Role-Based Access Control?
Role-Based Access Control (or RBAC) is a security model that restricts system access based on the roles assigned to users within an org. It provides a way to manage user permissions by associating users with specific roles and granting access to resources on their basis.
For e.g., in a WhatsApp group chat, you have a normal user and an admin. While the user can access necessary services such as sending and reading messages, admins get extra tooling like creating invite links or adding/removing users. This is how RBAC works in essence.
Implementing RBAC in ASP.NET Web APIs
Having spent a fair amount of time building web APIs with .NET, one of the easiest ways to implement RBAC that I discovered was by adding roles as claims in JWTs.
In case you aren't aware of what JWTs are, check out this Twitter thread I wrote last week:
RBAC is implemented via JWTs in ASP.NET through the following steps:
Step 1️⃣: Define roles for your application
Identify the different roles that users can have in your system. Examples of roles could be "admin," "everyone," "moderator," etc.
Step 2️⃣: Assign the roles
Associate specific roles with individual users. This can be stored in a database or any other persistent storage.
Step 3️⃣: Generate JWT
When a user authenticates, generate a JWT that includes the user's roles as claims in the payload.
The following NuGet packages are necessary for this purpose and must be imported at the top of your file via using directives, as shown:
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
Step 4️⃣: Protect API Endpoints
In your ASP.NET Web API controllers or actions that require authorization, apply the [Authorize] attribute to specify that the endpoint requires authentication. These may include specific roles as well.
Implement a JWT validation mechanism in your API to verify the authenticity and integrity of incoming JWTs. This may involve validating the issue, audience, signature, and token expiry.
builder.Services.AddAuthentication(opt=>{opt.DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;opt.DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(opt=>{opt.RequireHttpsMetadata=false;// for development onlyopt.SaveToken=true;opt.TokenValidationParameters=newTokenValidationParameters{ValidateIssuerSigningKey=true,IssuerSigningKey=newSymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["JWT:SecretKey"])),ValidateIssuer=true,ValidIssuer=builder.Configuration["JWT:Issuer"],ValidateAudience=true,ValidAudience=builder.Configuration["JWT:Audience"]};});
Step 6️⃣: Extract Roles from JWT
Once the JWT is validated, you can extract the user's roles from the JWT claims.
Step 7️⃣: Authorize Access
Finally, based on the roles extracted, implement the logic to allow or deny access to resources or actions within your API.
ASP.NET Web API sample to showcase JWT Token Authentication in .NET 6
JWT Authentication .NET Sample
Description
The JWT Authentication .NET Sample is an sample ASP.NET Web API to help understand how role based authentication can be implemented via JWTs in a .NET 6 application. It utilizes an InMemory database using Entity Framework Core for storing user data and the BCrypt library for encrypting passwords.
The API has 1 controller:
AuthController: Contains the login, registration, and test APIs
AuthController
The AuthController contains the login, registration, and test APIs we are using to get and try the JWT token authentication.
POST /auth/login
Returns the JWT token along with the user information from the database after the user enters their email and password.
Post Http Request Link: https://<YOUR-DOMAIN:PORT>//auth/login
To conclude, by implementing RBAC using JWTs, you can provide fine-grained access control to your resources based on the roles assigned to users, and allows for flexibility and scalability in managing access privileges within your application.