ASP.NET Core Authentication & Authorization Explained: What to Use, When, and How to Ship It Safely
A long, practical walkthrough of ASP.NET Core authentication and authorization on .NET 10: which mechanism fits which caller, where teams leave holes such as missing resource-level checks, and what to verify before going to production.
Key points
- Authentication produces a ClaimsPrincipal; authorization decides access, answering 401 when identity is unknown and 403 when it is known but not allowed.
- Choose by caller: cookie for server-rendered apps, BFF plus OIDC for SPAs, JWT Bearer for APIs, client credentials or managed identity for service-to-service, mTLS for high-trust internals.
- Resource-based checks are the step teams skip, which is how a user reads another record by editing an ID in the URL.
- Avoid building a token issuer unless identity is your product; IdentityServer4 is unmaintained, so use Entra ID, Keycloak, Duende or OpenIddict.
- Identity covers lockout, TOTP two-factor and, from .NET 10, passkey (WebAuthn/FIDO2) registration and sign-in.
- Keep issuer, audience, lifetime and signing-key validation on and tighten the default five-minute clock skew; also persist Data Protection keys across instances.
ASP.NET Core's security stack is capable but easy to misconfigure, and this guide walks it end to end for .NET 10. It opens with a familiar failure: every controller has [Authorize], tokens validate, yet editing /invoices/1042 to /invoices/1043 exposes another customer's invoice. Authentication said who the caller was; nobody checked whether they own that record.
The rest is a decision table: cookies for server-rendered pages, a BFF for SPAs, JWT Bearer for APIs, client credentials or managed identity for services, mTLS for high-trust links, and an external identity provider instead of a hand-rolled token server. Identity adds lockout, TOTP and, since .NET 10, passkeys. JWT validation must stay strict, and on .NET 10 cookie auth returns 401/403 for known API endpoints instead of redirecting to a login page.
Real-world use
- A multi-tenant SaaS whose /invoices/{id} endpoints must verify not only that the caller is signed in but that the record belongs to their tenant.
- A React SPA with an ASP.NET Core API behind a BFF, so only an HttpOnly cookie reaches the browser while tokens stay on the server.
- A background worker or scheduled job calling an internal API with client credentials or a managed identity instead of a shared secret.
- A corporate intranet already on Microsoft Entra ID, replacing a bespoke user table with cookie authentication plus OpenID Connect.
Why it matters
The access-control mistakes that leak data in ASP.NET Core apps are almost never exotic: a missing ownership check, a disabled token validation flag or a cookie that redirects where it should return 401. This guide names each one so you can audit your own services.
Related stories
- A secure enterprise chat with React, .NET 10 and Microsoft FoundryDEV Community: #dotnet1 d ago
- Mastering Rate Limiting and Resource Governance for MCP Servers at ScaleDEV Community: #aspnetcore1 d ago
- Faking a Yes: 6 Attacks on the Human Confirmation in a .NET 10 MCP ServerDEV Community: #dotnet2 d ago