Securing APIs is one of the most important aspects of modern application development. Whether you're building public APIs, mobile backends, or microservices, authentication and authorization ensure that only trusted clients and users can access protected resources.
OAuth has become the industry standard for delegated authorization, allowing applications to access resources on behalf of users without exposing their credentials. OAuth 2.1 builds upon OAuth 2.0 by simplifying the specification, removing insecure flows, and promoting modern security practices such as Proof Key for Code Exchange (PKCE).
In this article, you'll learn the core concepts of OAuth 2.1, how it integrates with ASP.NET Core APIs, and the best practices for building secure authentication systems.
What Is OAuth 2.1?
OAuth 2.1 is an evolution of OAuth 2.0 that consolidates security best practices and removes outdated authorization flows.
Unlike traditional username/password authentication, OAuth separates authentication from resource access.
A simplified request flow looks like this:
Client Application
│
Authorization Server
│
Access Token
│
ASP.NET Core API
The client obtains an access token from the authorization server and includes it in API requests.
The API validates the token before granting access to protected resources.
Why OAuth 2.1?
OAuth 2.1 improves security by removing older, less secure authorization flows and encouraging safer defaults.
Key improvements include:
Mandatory use of PKCE for authorization code flows
Removal of the Implicit Grant flow
Removal of the Resource Owner Password Credentials (ROPC) flow
Stronger guidance for refresh token handling
Emphasis on secure redirect URIs
These changes reduce common attack vectors while simplifying implementation.
OAuth Roles
OAuth defines several participants.
Resource Owner – The user who owns the protected data.
Client – The application requesting access.
Authorization Server – Authenticates users and issues tokens.
Resource Server – The API that validates tokens and serves protected resources.
Understanding these roles makes it easier to design secure authentication flows.
Authorization Code Flow with PKCE
For modern web, mobile, and desktop applications, the Authorization Code flow with PKCE is the recommended approach.
The process is:
User
│
Client Application
│
Authorization Server
│
Authorization Code
│
Access Token
│
ASP.NET Core API
PKCE protects authorization codes from interception by requiring the client to prove possession of a cryptographically generated secret during token exchange.
Today, this is considered the standard flow for interactive applications.
Configuring JWT Bearer Authentication
Most OAuth-protected APIs validate JWT access tokens.
Register JWT bearer authentication:
using Microsoft.AspNetCore.Authentication.JwtBearer;
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://your-auth-server";
options.Audience = "products-api";
});
Enable authentication and authorization:
app.UseAuthentication();
app.UseAuthorization();
The API now validates incoming bearer tokens automatically.
Protecting Endpoints
Use the Authorize attribute to secure API endpoints.
using Microsoft.AspNetCore.Authorization;
[Authorize]
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetProducts()
{
return Ok();
}
}
Unauthenticated requests receive an HTTP 401 Unauthorized response.
Authorization policies can further restrict access based on claims or roles.
Understanding Access Tokens
Access tokens represent the permissions granted to a client.
Typical JWT claims include:
Subject (
sub)Audience (
aud)Issuer (
iss)Expiration (
exp)Scopes
Roles
Join the conversation! Your thoughts help the community grow.