1 July 2017
In this post, we’ll dive into two crucial concepts for building secure web APIs: Authentication and Authorization. These concepts help ensure that only authorized users can access certain parts of your application. Specifically, we’ll focus on JWT (JSON Web Token) authentication and role-based authorization in .NET Core.
1. What is Authentication and Authorization?
Before we start, let’s clarify the difference between these two terms:
- Authentication: Verifying the identity of a user or service. This process ensures that the person or entity requesting access is who they say they are. In most cases, this is done by validating credentials like username and password.
- Authorization: Determining what actions or resources a user or service is allowed to access once their identity is authenticated. It’s about managing permissions and roles.
2. Setting Up JWT Authentication in .NET Core
For our example, we will use JWT for authentication, which is a compact and self-contained way to represent claims between two parties (such as a user and a server). It allows you to authenticate a user, and then securely transmit a token that proves their identity in subsequent requests.
Step 1: Install Necessary NuGet Packages
First, you need to install the required JWT authentication NuGet package in your .NET Core Web API project. Use the following command in the terminal:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Step 2: Configure JWT Authentication in Startup.cs
In your Startup.cs
file, you need to configure the JWT authentication in the ConfigureServices
method. This involves adding the JWT Bearer authentication middleware, which will validate incoming JWT tokens in HTTP requests.
Add the following code to the ConfigureServices
method:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false; // Set to true in production
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "YourIssuer", // Change this to your issuer
ValidAudience = "YourAudience", // Change this to your audience
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSuperSecretKey")) // Secret key
};
});
services.AddControllers();
}
This configuration tells the application to expect JWT tokens and validates them based on a few parameters, such as the Issuer, Audience, and the Signing Key.
Step 3: Add Authentication Middleware
In the Configure
method of Startup.cs
, you need to add the authentication middleware to ensure that JWT tokens are validated for incoming requests.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication(); // Add this line
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
This enables authentication and authorization middleware in the pipeline.
3. Implementing Role-Based Authorization
Now that we have authentication set up, let’s add role-based authorization. This allows you to control what resources or actions are available to users based on their roles.
Step 1: Add Roles to Your Claims
When you create a JWT token, you can add custom claims to it, including the roles the user belongs to. For example:
var claims = new[]
{
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, "Admin"), // Add role as a claim
new Claim(ClaimTypes.Role, "User")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSuperSecretKey"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "YourIssuer",
audience: "YourAudience",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
This code snippet adds Admin
and User
roles to the JWT token as claims. These roles will be used for authorization checks later.
Step 2: Protect Endpoints Using Roles
Now, let’s restrict access to certain endpoints based on roles. You can use the [Authorize]
attribute with the Roles
parameter to limit access to specific users.
For example, if you want only Admin
users to access an endpoint:
[Authorize(Roles = "Admin")]
[HttpGet("admin")]
public IActionResult GetAdminData()
{
return Ok(new { message = "Welcome Admin!" });
}
And if you want to allow both Admin
and User
roles:
[Authorize(Roles = "Admin,User")]
[HttpGet("data")]
public IActionResult GetData()
{
return Ok(new { message = "Welcome User or Admin!" });
}
This approach ensures that only users with the correct roles can access specific resources or actions.
4. Testing JWT Authentication and Authorization
Once you’ve implemented JWT authentication and role-based authorization, it’s time to test everything.
- First, authenticate a user by providing their credentials (e.g., username and password).
- If the credentials are valid, issue a JWT token and send it back to the client.
- For subsequent requests, include the token in the
Authorization
header as a Bearer token:
Authorization: Bearer <your-jwt-token>
Use tools like Postman or cURL to simulate the authentication flow and test the access control on protected endpoints.
5. Conclusion
In this post, we covered the essentials of authentication and authorization in .NET Core Web APIs. You learned how to:
- Set up JWT authentication for secure communication.
- Implement role-based authorization to control access based on user roles.
- Protect API endpoints using the
[Authorize]
attribute.
By adding these features to your Web API, you can secure your application and ensure that only authorized users can access certain resources or actions.
Happy coding, and stay secure!