C# tutorials > Frameworks and Libraries > ASP.NET Core > Authentication and Authorization (Identity, JWT, custom policies)
Authentication and Authorization (Identity, JWT, custom policies)
This tutorial explores authentication and authorization in ASP.NET Core, covering Identity, JWT (JSON Web Tokens), and custom policies. Authentication verifies a user's identity, while authorization determines what resources they can access. We'll provide code snippets and explanations to help you implement secure applications.
Understanding Authentication and Authorization
Authentication is the process of verifying the identity of a user or service. Common methods include username/password, social logins (like Google or Facebook), and API keys. Authorization is the process of determining what an authenticated user is allowed to do. This is often managed through roles and permissions. In ASP.NET Core, these processes are typically handled by Identity, JWT, or custom-built solutions.
ASP.NET Core Identity
ASP.NET Core Identity is a framework for managing user authentication and authorization. It provides features for user registration, login, password management, and role-based access control. It's a solid starting point for many web applications.
Setting up ASP.NET Core Identity
This code snippet demonstrates how to set up ASP.NET Core Identity in your Startup.cs
file. It configures the database context, adds Identity services, and optionally adds roles. The AddDefaultIdentity
method registers the necessary services for Identity. Replace ApplicationDbContext
with your actual DbContext implementation, and update the connection string accordingly. It also creates the roles 'Administrator', 'Editor', and 'User' if they don't already exist.
csharp
// Startup.cs (ConfigureServices method)
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
// Create Roles
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
var roleManager = serviceScope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var roles = new[] { "Administrator", "Editor", "User" };
foreach (var role in roles)
{
if (!await roleManager.RoleExistsAsync(role))
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
}
Using Roles for Authorization
The [Authorize]
attribute is used to restrict access to specific controllers or action methods based on roles. In this example, only users with the 'Administrator' or 'Editor' role can access the AdminPanel
action. Make sure to add this attribute to your controller, and that your identity user has been assigned to one of the roles to be able to view the page.
csharp
// Controller or Action Method
[Authorize(Roles = "Administrator,Editor")]
public IActionResult AdminPanel()
{
return View();
}
JSON Web Tokens (JWT)
JWTs are a standard for securely transmitting information as a JSON object. They are commonly used for stateless authentication, where the server doesn't need to maintain session information for each user. The client sends the JWT with each request, and the server verifies its validity.
Generating a JWT
This code snippet shows how to generate a JWT using the Don't forget to configure your JWT settings in appsettings.json like this :System.IdentityModel.Tokens.Jwt
library. It creates a set of claims (user information), signs the token with a secret key, and sets an expiration date. Store your JWT secret key in a secure configuration file (e.g., appsettings.json
) and never hardcode it in your code."Jwt": {
"Key": "Your_Secret_Key_Here",
"Issuer": "Your_Issuer",
"Audience": "Your_Audience",
"ExpireDays": "7"
}
csharp
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
// Example method to generate a JWT
private string GenerateJwtToken(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
// Add roles as claims
var roles = _userManager.GetRolesAsync(user).Result;
foreach (var role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["Jwt:ExpireDays"]));
var token = new JwtSecurityToken(
_configuration["Jwt:Issuer"],
_configuration["Jwt:Audience"],
claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
Configuring JWT Authentication
This code configures JWT authentication in your Startup.cs
file. It sets up the JwtBearer
authentication scheme and defines the token validation parameters. This ensures that only valid JWTs issued by your application are accepted. The UseAuthentication
and UseAuthorization
middleware are added to the pipeline to enable authentication and authorization.
csharp
// Startup.cs (ConfigureServices method)
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddAuthorization();
// Startup.cs (Configure method)
app.UseAuthentication();
app.UseAuthorization();
Protecting APIs with JWT
The [Authorize]
attribute is used to protect your APIs with JWT authentication. Only users with a valid JWT can access the Get
action method. You must send the JWT token as the 'Authorization' header. Example : Authorization: Bearer YOUR_JWT_TOKEN
csharp
// Controller or Action Method
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]")]
public class SecuredController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("This API endpoint is secured by JWT.");
}
}
Custom Policies
Custom policies provide a more flexible way to define authorization rules. They allow you to create policies based on claims, roles, or any other criteria specific to your application. For example, you might create a policy that requires users to have a certain claim value or be a member of a specific group.
Creating a Custom Policy
This code snippet shows how to create a custom policy named 'MustBeOver18'. It requires users to have a 'DateOfBirth' claim and ensures that they are at least 18 years old. The policy evaluates the 'DateOfBirth' claim and returns true if the user is over 18, otherwise, it returns false.
csharp
// Startup.cs (ConfigureServices method)
services.AddAuthorization(options =>
{
options.AddPolicy("MustBeOver18", policy =>
policy.RequireClaim("DateOfBirth", claim =>
{
if (DateTime.TryParse(claim.Value, out DateTime dob))
{
return dob.AddYears(18) <= DateTime.Now;
}
return false;
}));
});
Using a Custom Policy
The [Authorize]
attribute is used to apply the custom policy to the AdultContent
action method. Only users who satisfy the 'MustBeOver18' policy can access this action. Make sure the users have the DateOfBirth claim configured with their JWT to be able to access this page.
csharp
// Controller or Action Method
[Authorize(Policy = "MustBeOver18")]
public IActionResult AdultContent()
{
return View();
}
Concepts Behind the Snippet
The core concept is to decouple authentication and authorization from the application logic. Identity manages user accounts, JWT provides stateless authentication, and custom policies allow fine-grained control over access to resources.
Real-Life Use Case Section
Consider an e-commerce platform. Identity manages user accounts and logins. JWTs are used for API authentication between microservices. Custom policies might be used to allow only users with a 'Premium' subscription to access certain features.
Best Practices
Interview Tip
Be prepared to explain the difference between authentication and authorization. Also, understand the strengths and weaknesses of different authentication methods, such as Identity vs. JWT. Be prepared to discuss best practices for securing your application.
When to Use Them
Memory Footprint
Identity with database persistence has a higher memory footprint due to session management (if enabled) and database connections. JWT is more lightweight as it's stateless. Custom policies themselves don't significantly impact memory, but complex policies can increase processing time.
Alternatives
Pros
Cons
FAQ
-
What is the difference between authentication and authorization?
Authentication is the process of verifying a user's identity, while authorization is the process of determining what resources an authenticated user can access.
-
How do I secure my JWT secret key?
Store your JWT secret key in a secure configuration file (e.g.,
appsettings.json
) and never hardcode it in your code. Consider using environment variables or a secrets management service for even greater security. -
How do I handle token expiration?
Implement token refresh mechanisms to allow users to continue using your application without having to re-authenticate frequently. Set appropriate expiration times based on your security requirements.
-
How do I add custom claims to a JWT?
You can add custom claims to a JWT by adding them to the
Claims
collection when generating the token. Make sure to use meaningful and well-defined claim names.