OAuth 2.0
ActiveOAuth 2.0 is an authorization framework (RFC 6749) that enables third-party applications to obtain limited access to a user's resources without exposing credentials. Instead of sharing username/password, a user grants an application an access token with specific scopes. OAuth 2.0 defines four grant types for different client types and use cases. It is the foundation for API authorization across every major platform – Google, GitHub, Stripe, Salesforce.
In one line
OAuth 2.0 (RFC 6749, 2012) is the industry standard for API authorization. Clients obtain access tokens from an authorization server; tokens are presented to resource servers. Four grant types: Authorization Code (web apps), Authorization Code + PKCE (mobile/SPA), Client Credentials (server-to-server), Device Flow (CLI/TV). Scopes limit what a token can access. Bearer tokens (RFC 6750) sent as Authorization: Bearer <token>. OAuth 2.1 draft consolidates best practices: PKCE required everywhere, implicit and password grants removed.
Quick Reference
| Field | Size | Description |
|---|---|---|
| Grant types | 4 active + 1 deprecated | Authorization Code (web apps), Authorization Code + PKCE (public clients), Client Credentials (M2M), Device Flow (CLI/TV/IoT). Implicit (deprecated). Resource Owner Password (deprecated per OAuth 2.1). |
| Access token | Bearer token | Opaque string or JWT. Presented in Authorization: Bearer <token> header. Short-lived (typically 1 hour). Resource servers validate without calling authorization server (if JWT) or via introspection (RFC 7662). |
| Refresh token | Long-lived secret | Used to obtain new access tokens without user re-authentication. Stored securely server-side (never in browser). Rotate refresh tokens on each use (RFC 6749 §10.4). Not issued in Client Credentials flow. |
| Scopes | Space-separated strings | Limit access: read:users write:orders. Requested by client, granted by user, embedded in token. Principle of least privilege – request only the scopes you need. |
| Authorization code | Short-lived, one-time | Exchanged for tokens in Authorization Code flow. Single use. Expires in ~10 minutes. PKCE binds the code to the code_verifier to prevent interception attacks. |
| PKCE | RFC 7636 | code_verifier: cryptographically random string (43–128 chars). code_challenge: BASE64URL(SHA256(code_verifier)). Required for all public clients (mobile, SPA). Required in OAuth 2.1 for all flows. |
| Token endpoint | POST /oauth/token | POST with grant_type, code/credentials, client_id, client_secret (confidential clients). Returns access_token, token_type, expires_in, refresh_token, scope. |
| Bearer token | RFC 6750 | Authorization: Bearer eyJhbGciOiJSUzI1NiIs... Tokens must be kept secret – any bearer can use them. Use HTTPS always. Never log tokens. |
Key Characteristics
Delegated authorization
Users grant specific scopes to third-party apps without sharing credentials. The app gets a token limited to those scopes. Users can revoke tokens at any time.
Authorization not authentication
OAuth 2.0 is an authorization framework, not an authentication protocol. It tells you what a token can access, not who the user is. Use OpenID Connect (OIDC) on top of OAuth 2.0 for user identity.
Separation of concerns
Authorization Server (issues tokens) and Resource Server (validates tokens) are separate. Token validation can be done offline with JWTs or via introspection endpoint (RFC 7662).
PKCE is mandatory now
OAuth 2.1 mandates PKCE for all authorization code flows. Browser apps and mobile apps should always use PKCE even without OAuth 2.1. Prevents authorization code interception via redirect URI hijacking.
Message Format
# Authorization Code + PKCE flow
# Step 1: Generate PKCE
code_verifier = base64url(crypto.randomBytes(32)) // 43–128 chars
code_challenge = base64url(sha256(code_verifier))
# Step 2: Redirect user to authorization server
GET https://auth.example.com/authorize?
response_type=code
&client_id=app_abc
&redirect_uri=https://app.example.com/callback
&scope=read:profile+write:orders
&state=random-csrf-token
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
# Step 3: Exchange code for tokens
POST https://auth.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=abc123
&redirect_uri=https://app.example.com/callback
&client_id=app_abc
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk# Token response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
"scope": "read:profile write:orders"
}
# Use access token
GET /api/v1/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
# Refresh when expired
POST /oauth/token
grant_type=refresh_token
&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=app_abc
# Client Credentials (server-to-server, no user)
POST /oauth/token
grant_type=client_credentials
&client_id=svc_abc
&client_secret=secret_xyz
&scope=read:orders