Microsoft Docs

Authentication and Authorization in ASP.NET Core

This document provides a comprehensive guide to implementing authentication and authorization in your ASP.NET Core applications. Secure your applications by understanding how to verify user identities and control access to resources.

Introduction

Authentication is the process of verifying who a user is. Authorization is the process of determining what an authenticated user is allowed to do. ASP.NET Core provides a flexible and extensible framework for handling both.

This guide covers the core concepts and common implementation patterns for securing your web applications and APIs.

Authentication

Authentication involves identifying users, often by checking credentials like usernames and passwords, tokens, or certificates. ASP.NET Core's authentication middleware pipeline allows you to plug in various authentication schemes.

JWT Bearer Authentication

JSON Web Token (JWT) bearer authentication is frequently used for APIs and single-page applications (SPAs). A JWT is a compact, URL-safe means of representing claims to be transferred between two parties. The server issues a token upon successful login, and the client includes this token in the Authorization header of subsequent requests.

Setup:

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

app.UseAuthentication();
app.UseAuthorization();

This configuration validates the JWT token, ensuring its issuer, audience, and signature are correct. The secret key used for signing must be kept secure.

External Authentication Providers

ASP.NET Core supports integration with external authentication providers like Google, Facebook, Microsoft, and Twitter through OAuth or OpenID Connect. This allows users to log in using their existing accounts on these platforms.

Setup Example (Google):

services.AddAuthentication().AddGoogle(options =>
{
    options.ClientId = Configuration["Authentication:Google:ClientId"];
    options.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
});

You will need to register your application with the chosen provider to obtain client IDs and secrets.

Authorization

Once a user is authenticated, you need to determine if they have permission to access a specific resource or perform an action. ASP.NET Core provides powerful authorization mechanisms.

Role-Based Authorization

Role-based authorization grants permissions based on the roles assigned to a user. For example, an "Admin" role might have access to administrative features, while a "User" role has standard access.

Implementation:

[Authorize(Roles = "Admin")]
public IActionResult AdminDashboard()
{
    // This action is only accessible to users in the "Admin" role
    return View();
}

The [Authorize] attribute can be applied to controllers or actions to enforce role-based access control.

Policy-Based Authorization

Policy-based authorization offers more flexibility by defining authorization policies that can combine multiple requirements, such as roles, claims, or custom logic. This allows for more granular control.

Defining a Policy:

services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
    options.AddPolicy("MinimumAge", policy => policy.RequireAssertion(context =>
    {
        var ageClaim = context.User.FindFirst("Age");
        if (ageClaim != null && int.Parse(ageClaim.Value) >= 18)
        {
            return true;
        }
        return false;
    }));
});

Using a Policy:

[Authorize(Policy = "RequireAdminRole")]
public IActionResult SensitiveData()
{
    // Access requires the "Admin" role
    return View();
}

[Authorize(Policy = "MinimumAge")]
public IActionResult AdultContent()
{
    // Access requires the user to be at least 18
    return View();
}

Policies are registered in the ConfigureServices method and then applied using the Policy parameter of the [Authorize] attribute.

Resource-Based Authorization

Resource-based authorization allows you to control access to specific instances of resources. For example, a user might be allowed to edit their own profile but not the profiles of others.

This typically involves creating custom authorization requirements and handlers that inspect the resource being accessed and the current user's identity and claims.

Example Scenario: Editing Own Profile

You would create an authorization requirement like CanEditProfileRequirement and an associated handler that checks if the UserId associated with the profile matches the UserId claim of the authenticated user.

public class CanEditProfileRequirement : IAuthorizationRequirement { }

public class CanEditProfileHandler : AuthorizationHandler<CanEditProfileRequirement, Profile>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CanEditProfileRequirement requirement, Profile resource)
    {
        if (context.User.IsInRole("Admin"))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (userId != null && resource.OwnerUserId == userId)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

And then register and use it:

services.AddAuthorization(options =>
{
    options.AddPolicy("CanEditOwnProfile", policy =>
        policy.AddRequirements(new CanEditProfileRequirement()));
});

// In a controller or Razor Page:
[Authorize(Policy = "CanEditOwnProfile")]
public IActionResult EditProfile(int id)
{
    // ... logic to fetch profile and check authorization
    return View();
}

Advanced Topics

  • Identity: Understanding the IdentityUser model and its extensions.
  • Claims: Using claims to represent user attributes and permissions.
  • Custom Authentication/Authorization: Building your own authentication schemes and authorization providers.
  • API Security: Specific considerations for securing Web APIs, including OAuth 2.0 and OpenID Connect.
  • Data Protection: How ASP.NET Core uses data protection APIs for things like anti-forgery tokens and cookie encryption.

For more in-depth information on these topics, please refer to the official ASP.NET Core documentation.