What is OAuth 2.0?
OAuth 2.0 is a delegation framework. It lets a client application obtain limited access to an HTTP API on behalf of a resource owner (usually a user), or on its own behalf, without ever handling the owner’s password. The client receives an access token scoped to what was granted, and presents it to the API.
OAuth 2.0 is authorization, not authentication. An access token says what the bearer may do, not who the user is. If you need identity, use OpenID Connect, which adds an ID Token on top of the same flows.
The core is two RFCs: RFC 6749 (the framework) and RFC 6750 (bearer token usage). A decade of extensions and security fixes sit around them, and OAuth 2.1 consolidates the parts that survived into one document. OAuth 2.1 is still an Internet-Draft (draft-ietf-oauth-v2-1, revision 16 at the time of writing), not an RFC, so cite RFC 6749 plus RFC 9700 when you need a published standard.
1. Roles and Endpoints
| Role | Responsibility |
|---|---|
| Resource owner | The entity that can grant access, typically the end user |
| Client | The application requesting access. Confidential clients can keep a secret; public clients (SPAs, mobile and desktop apps) cannot |
| Authorization server | Authenticates the owner, obtains consent, and issues tokens |
| Resource server | The API, which accepts and validates access tokens |
The authorization server exposes an authorization endpoint (browser redirects) and a token endpoint (back-channel POST requests). Token responses carry Cache-Control: no-store so no intermediary keeps a copy.
2. Grant Types
| Grant | RFC 6749 | OAuth 2.1 | Use it for |
|---|---|---|---|
| Authorization code (with PKCE) | Yes | Yes | Any client acting for a user |
| Client credentials | Yes | Yes | Service-to-service calls with no user |
| Refresh token | Yes | Yes | Renewing access without re-prompting the user |
Implicit (response_type=token) |
Yes | Removed | Nothing. Use authorization code with PKCE |
| Resource owner password credentials | Yes | Removed | Nothing. The client sees the password, which defeats the point |
The device authorization grant (RFC 8628) covers input-constrained devices such as TVs and CLIs. For choosing between client credentials and user-delegated flows in practice, see OAuth 2.0 & API Keys.
3. Authorization Code with PKCE
PKCE (RFC 7636) binds the authorization request to the token request. The client generates a random code_verifier, sends its SHA-256 hash as the code_challenge, and later proves possession by sending the verifier itself. An attacker who intercepts the code cannot redeem it.
GET /authorize?response_type=code &client_id=s6BhdRkqt3 &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcb &scope=orders%3Aread &state=xyz123 &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM &code_challenge_method=S256 HTTP/1.1Host: auth.example.comPOST /token HTTP/1.1Host: auth.example.comContent-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcb&client_id=s6BhdRkqt3&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkHTTP/1.1 200 OKContent-Type: application/jsonCache-Control: no-store
{ "access_token": "2YotnFZFEjr1zKboUfz2xA", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", "scope": "orders:read"}Always use S256. The plain method sends the verifier as the challenge and protects nothing if the authorization request leaks.
4. Using Bearer Tokens
RFC 6750 defines three ways to send a bearer token; only the Authorization header is worth using. A token in a query string ends up in server logs, browser history and Referer headers, and RFC 9700 forbids it outright.
GET /v1/orders HTTP/1.1Host: api.example.comAuthorization: Bearer 2YotnFZFEjr1zKboUfz2xAWhen a token is rejected, the resource server responds with a WWW-Authenticate challenge and the status RFC 6750 assigns to each error code:
error |
Status | Meaning |
|---|---|---|
invalid_request |
400 Bad Request |
Malformed request, missing or duplicated parameters |
invalid_token |
401 Unauthorized |
Expired, revoked, malformed or otherwise invalid token |
insufficient_scope |
403 Forbidden |
Valid token without the required scope |
Access tokens are often JWTs so resource servers can validate them locally, but RFC 6749 does not require any format. Clients should treat them as opaque strings and never parse them.
5. The Security BCP (RFC 9700)
RFC 9700 (BCP 240, January 2025) updates RFC 6749 and RFC 6750 with what a decade of attacks taught. Its core requirements, most of which OAuth 2.1 adopts:
- Authorization servers must compare redirect URIs by exact string match (only the port may vary for native-app loopback redirects).
- Public clients must use PKCE; it is recommended for confidential clients too, and authorization servers must support it.
- Clients should not use the implicit grant, and the password grant must not be used.
- Access tokens must not be passed in a URI query parameter.
- Refresh tokens for public clients must be sender-constrained or rotated on every use.
- Access tokens should be audience-restricted to one resource server, and sender-constrained with mutual TLS (RFC 8705) or DPoP (RFC 9449) where possible.
Treat RFC 9700 as the baseline for any new deployment. “Supports OAuth 2.0” without it describes a server vulnerable to attacks that have been public for years.
6. Revocation, Introspection and Metadata
Three extensions turn the framework into something operable:
| Spec | Endpoint | Purpose |
|---|---|---|
| RFC 7009 | Revocation | Client tells the server a token is no longer needed (logout, uninstall) |
| RFC 7662 | Introspection | Resource server asks whether a token is active and what it grants |
| RFC 8414 | /.well-known/oauth-authorization-server |
Authorization server publishes its endpoints and capabilities |
RFC 8414 metadata lists issuer, authorization_endpoint, token_endpoint, revocation_endpoint, introspection_endpoint and code_challenge_methods_supported, among others. Clients must check that the issuer in the document matches the issuer they used to build the URL. Its counterpart for APIs, Protected Resource Metadata (RFC 9728), lets a resource server point clients at its authorization server; the Model Context Protocol requires it.
Token lifetimes, refresh rotation and when to introspect rather than validate locally are covered in Token Lifecycle.