dotnet-authentication
ASP.NET Core authentication and authorization
Two questions, never one. Authentication answers who the caller is and hands you a ClaimsPrincipal. Authorization answers what that principal may do. The framework keeps them as separate middlewares - UseAuthentication() then UseAuthorization(), in that order - and so should your thinking. A 401 means the framework could not establish identity; a 403 means it knows who you are and the answer is still no.
Baseline is .NET 8 / C# 12. On .NET Framework 4.8 the OWIN / Katana + ASP.NET Identity 2.x auth stack is in references/net-framework-48.md.
Pick the scheme from the surface
The right authentication scheme is decided by what kind of client talks to the endpoint, not by preference:
- Stateless REST API -> JWT bearer (
Microsoft.AspNetCore.Authentication.JwtBearer). The token carries the identity; the server keeps no session. - Server-rendered app (MVC, Razor Pages, Blazor Server) -> cookie authentication. The browser already holds a cookie; use it.
- Delegated identity / single sign-on -> OpenID Connect, with an external provider doing the actual sign-in.
Do not invent a user store. ASP.NET Identity already solves password hashing (PBKDF2 by default), account lockout, two-factor, and email confirmation - all the places a hand-rolled store quietly gets wrong. On .NET 8+, MapIdentityApi<TUser>() emits ready-made register / login / refresh / 2FA endpoints when those defaults fit; reach past it only when the contract genuinely differs.
JWT bearer for APIs
Register the scheme and lock down validation: