Authentication and ASP.NET Core Identity

This section documents ASP.NET Core on .NET 10 (LTS), the current release — the minimal hosting model, the middleware pipeline, dependency injection, Minimal APIs, MVC & Razor Pages, Blazor with the current render modes, SignalR and gRPC, EF Core, ASP.NET Core Identity and policy-based authorization, output caching, rate limiting, and Native-AOT-aware building — as described by the official documentation at Microsoft Learn, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. .NET ships a major release every November and its APIs continue to evolve: the examples here target .NET 10 / C# 14.

This section’s bibliography lists the reference material consulted while preparing these pages.

Authentication establishes who the caller is; authorization (next page) decides what they may do. Authentication is configured as one or more named schemes, each backed by a handler.

Schemes and handlers

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie()
    .AddJwtBearer();               // a second scheme, selected per endpoint

var app = builder.Build();
app.UseAuthentication();           // populate HttpContext.User
app.UseAuthorization();

After UseAuthentication, HttpContext.User is a ClaimsPrincipal — a set of Claim name/value pairs (ClaimTypes.NameIdentifier, ClaimTypes.Email, roles, and app-specific claims). See Overview of ASP.NET Core authentication.

For server-rendered apps that manage their own sign-in:

builder.Services.AddAuthentication("Cookies").AddCookie("Cookies", o =>
{
    o.LoginPath = "/account/login";
    o.ExpireTimeSpan = TimeSpan.FromHours(8);
    o.SlidingExpiration = true;
});

// in the login endpoint, after verifying credentials:
var claims = new List<Claim> { new(ClaimTypes.Name, user.Email), new(ClaimTypes.NameIdentifier, user.Id) };
var identity = new ClaimsIdentity(claims, "Cookies");
await HttpContext.SignInAsync("Cookies", new ClaimsPrincipal(identity));
// sign out:
await HttpContext.SignOutAsync("Cookies");

In .NET 10 the cookie handler returns 401 / 403 for endpoints that look like APIs instead of redirecting to the login page. See Cookie authentication.

JWT bearer

For APIs called with an Authorization: Bearer <token> header:

builder.Services.AddAuthentication().AddJwtBearer(o =>
{
    o.Authority = "https://login.example.com";           // issuer; keys fetched from its metadata
    o.Audience  = "orders-api";
    o.TokenValidationParameters = new()
    {
        ValidateIssuer = true, ValidateAudience = true,
        ValidateLifetime = true, ValidateIssuerSigningKey = true,
    };
});

OAuth 2.0 and OpenID Connect

Delegate sign-in to an identity provider with the authorization-code flow + PKCE:

builder.Services.AddAuthentication(o =>
{
    o.DefaultScheme = "Cookies";
    o.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", o =>
{
    o.Authority = "https://login.example.com";
    o.ClientId = "web-app";
    o.ClientSecret = builder.Configuration["Oidc:ClientSecret"];   // from a secret store
    o.ResponseType = "code";
    o.UsePkce = true;
    o.Scope.Add("profile");
    o.SaveTokens = true;
});

AddOAuth handles providers that speak plain OAuth 2.0; the Microsoft.AspNetCore.Authentication.Google / .MicrosoftAccount / .GitHub packages add social logins; Microsoft.Identity.Web integrates Microsoft Entra ID. See external provider authentication.

ASP.NET Core Identity

Identity is the full local-accounts system — user store, password hashing, sign-in, 2FA, lockout, email confirmation:

builder.Services.AddDbContext<AppIdentityDbContext>(o => o.UseSqlServer(cs));
builder.Services.AddIdentity<AppUser, IdentityRole>(o =>
    {
        o.Password.RequiredLength = 12;
        o.SignIn.RequireConfirmedEmail = true;
        o.Lockout.MaxFailedAccessAttempts = 5;
    })
    .AddEntityFrameworkStores<AppIdentityDbContext>()
    .AddDefaultTokenProviders();

// working with users
public sealed class AccountService(UserManager<AppUser> users, SignInManager<AppUser> signIn)
{
    public Task<IdentityResult> RegisterAsync(string email, string password)
        => users.CreateAsync(new AppUser { UserName = email, Email = email }, password);

    public Task<SignInResult> LoginAsync(string email, string password)
        => signIn.PasswordSignInAsync(email, password, isPersistent: true, lockoutOnFailure: true);
}

UserManager<T> / SignInManager<T> / RoleManager<T> are the APIs; scaffold the Identity Razor UI (dotnet aspnet-codegenerator identity) for ready-made register/login/manage pages. 2FA uses a TOTP authenticator (a QR-code enrolment page) or email/SMS codes; external logins, password reset, and lockout are built in; a custom IUserStore<T> swaps the storage. See Introduction to Identity.

Identity API endpoints and other schemes

MapIdentityApi<AppUser>() exposes register / login / refresh / 2FA endpoints that return bearer tokens for SPA and mobile clients:

builder.Services.AddIdentityApiEndpoints<AppUser>().AddEntityFrameworkStores<AppIdentityDbContext>();
app.MapGroup("/auth").MapIdentityApi<AppUser>();

Also available: certificate authentication (AddCertificate), Windows/Negotiate authentication (AddNegotiate), and simple API keys implemented as a custom AuthenticationHandler.

The OpenID Connect authorization-code flow

sequenceDiagram participant U as User (browser) participant A as ASP.NET Core app participant I as Identity provider U->>A: GET /orders (no session) A-->>U: 302 to I /authorize?response_type=code&code_challenge=... U->>I: follow redirect, sign in + consent I-->>U: 302 back to /signin-oidc?code=abc U->>A: GET /signin-oidc?code=abc A->>I: POST /token (code + code_verifier + client secret) I-->>A: id_token + access_token (+ refresh_token) A-->>U: set auth cookie, 302 to /orders U->>A: GET /orders (authenticated)