OAuth 2.0: What It Is and How It Works
Updated: August 2026
OAuth 2.0 is an authorization framework that lets applications access resources on behalf of a user without ever seeing that user's password. It solves the fundamental problem of delegated access: granting limited permissions to third parties without sharing credentials.
If you build APIs or web applications in .NET, you will use OAuth. This guide covers the core concepts, grant types, security best practices, and how to implement OAuth with Duende IdentityServer.
What Is OAuth?
OAuth 2.0 is an open standard for authorization, defined in RFC 6749. It provides a protocol for granting scoped, time-limited access to protected resources through access tokens rather than credentials.
OAuth does not handle authentication (proving who a user is). It handles authorization (proving what an application is allowed to do). Authentication is the job of OpenID Connect, which builds on OAuth.
Why Does OAuth Exist?
Before OAuth, applications that needed access to a user's data on another service had one option: ask for the user's username and password. This created serious problems:
- Over-provisioned access. The application received full access to the user's account, not just what it needed.
- Password exposure. Every third-party application stored user credentials, multiplying breach risk.
- No revocation. Users could not revoke access to one application without changing their password everywhere.
- No audit trail. No way to distinguish actions taken by the user from actions taken by a third party.
OAuth eliminates password sharing by introducing tokens with limited scope and lifetime. Users grant specific permissions to specific applications, and they can revoke those permissions at any time.
What Are the Key OAuth Terms?
Understanding OAuth requires knowing seven roles and concepts:
| Term | Definition |
|---|---|
| Resource Owner | The user who owns the data and grants access |
| Client | The application requesting access on behalf of the user |
| Authorization Server | The server that authenticates the user and issues tokens (e.g., Duende IdentityServer) |
| Resource Server | The API that holds the protected data and accepts access tokens |
| Access Token | A credential representing the granted permissions, sent with each API request |
| Refresh Token | A credential used to obtain new access tokens without re-prompting the user |
| Scopes | Named permissions that define what the client can do (e.g., |
How Does OAuth Work?
The core flow follows this pattern:
- Client requests authorization from the Resource Owner via the Authorization Server
- Resource Owner grants permission (typically through a consent screen)
- Authorization Server issues tokens to the Client
- Client presents the access token to the Resource Server
- Resource Server validates the token and serves the request
The specific steps vary by grant type, but every OAuth flow produces an access token that the client uses to call protected APIs.
What Are the OAuth 2.0 Grant Types?
OAuth defines several grant types for different application architectures. Use this table to pick the right one:
| Grant Type | Use Case | Client Type | User Involved? |
|---|---|---|---|
| Authorization Code + PKCE | Web apps, mobile apps, SPAs | Public or confidential | Yes |
| Client Credentials | Machine-to-machine, background services | Confidential only | No |
| Device Authorization | Smart TVs, CLI tools, IoT devices | Public | Yes |
Authorization Code with PKCE
This is the recommended grant for any application where a user is present. The client redirects the user to the authorization server, receives an authorization code, and exchanges that code for tokens.
PKCE (Proof Key for Code Exchange, defined in RFC 7636) protects against authorization code interception attacks. Every client, whether public or confidential, should use PKCE.
Client Credentials
Use Client Credentials when no user is involved. A backend service authenticates directly with the authorization server using its own credentials (client ID and secret) and receives an access token for calling downstream APIs.
Device Authorization
Use Device Authorization for input-constrained devices. The device displays a code, the user enters that code on a separate device with a browser, and the device polls the authorization server until authorization completes.
Which Grant Types Are Deprecated?
Two grants from the original OAuth 2.0 spec are now discouraged:
| Deprecated Grant | Why |
|---|---|
| Implicit | Tokens exposed in browser URL fragments. No refresh tokens. Vulnerable to token leakage. Replaced by Authorization Code + PKCE. |
| Resource Owner Password Credentials (ROPC) | Requires the client to collect user credentials directly. Defeats the entire purpose of OAuth. No support for MFA. |
Do not use these grants in new applications. The OAuth 2.1 draft specification removes both.
How Does OAuth Relate to OpenID Connect?
OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0. Where OAuth answers "what can this app do?", OIDC answers "who is this user?"
OIDC adds:
- An ID Token (a JWT containing user identity claims)
- A UserInfo endpoint for retrieving profile data
- A discovery document for client configuration
- Standard scopes like
openid,profile, andemail
You almost always need both. OAuth provides the access token for API calls. OIDC provides the ID token for sign-in. Duende IdentityServer supports both protocols in a single deployment.
Read the OpenID Connect specification for the full protocol definition.
What Are OAuth Security Best Practices?
Follow these practices to secure your OAuth implementation:
- Always use PKCE. Every authorization code flow, regardless of client type, should include PKCE (RFC 7636).
- Keep access tokens short-lived. Issue tokens with lifetimes of minutes, not hours. Use refresh tokens for long sessions.
- Validate tokens at the resource server. Check signature, issuer, audience, expiration, and scopes on every request.
- Use sender-constrained tokens. DPoP and mTLS bind tokens to a specific client, preventing token theft (Duende IdentityServer DPoP support).
- Restrict scopes. Grant the minimum permissions each client needs. Never issue a wildcard scope.
- Rotate refresh tokens. Issue a new refresh token with each use and invalidate the old one.
- Use Pushed Authorization Requests (PAR). PAR prevents request tampering by sending authorization parameters directly to the server (Duende IdentityServer PAR support).
How Does Duende IdentityServer Implement OAuth?
Duende IdentityServer is a standards-compliant OAuth 2.0 and OpenID Connect framework for ASP.NET Core. It gives you full control over your authorization server: your infrastructure, your data, your policies.
IdentityServer supports:
- All recommended OAuth 2.0 grant types
- OpenID Connect for authentication
- Token security features (DPoP, mTLS, PAR, JAR)
- Dynamic Client Registration
- Server-side sessions
- Entity Framework Core integration for persistent configuration
Configuring an OAuth Client
Here is a minimal authorization code client configuration in Duende IdentityServer:
Csharp
using Duende.IdentityServer.Models;
var clients = new List<Client>
{
new Client
{
ClientId = "webapp",
ClientName = "My Web Application",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "https://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
"openid",
"profile",
"api1"
},
AllowOfflineAccess = true // enables refresh tokens
}
}; This configuration defines a confidential client that uses the Authorization Code flow with PKCE. The client can request the openid, profile, and api1 scopes, and it can obtain refresh tokens for long-lived sessions.
Protecting an API with Bearer Tokens
On the resource server side, configure JWT bearer authentication to validate access tokens issued by IdentityServer:
Csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5001";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false // audience is validated via scope policy below
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});The resource server validates every incoming token against the authorization server's signing keys, checks the issuer, and enforces scope requirements.
How Do You Get Started with OAuth in .NET?
Start building your OAuth implementation today:
- Read the fundamentals in the Duende IdentityServer documentation
- Follow the quickstarts to configure your first authorization server, API, and client
- Explore token management with Duende.AccessTokenManagement for handling token refresh in your clients
- Secure your SPAs using the Duende BFF Security Framework
Try Duende IdentityServer
Duende IdentityServer gives you a production-ready OAuth 2.0 and OpenID Connect implementation that you own and control. Configure it for your exact requirements, deploy it on your infrastructure, and integrate it with your existing ASP.NET Core applications.
Get started with the quickstarts or explore the full documentation.