Definition
Have you ever clicked “Sign in with Google” or “Continue with Facebook” on a website? That is OAuth 2.0 in action. It is the industry-standard protocol that lets you grant applications limited access to your accounts without sharing your password. Instead of trusting every app with your actual credentials, OAuth lets you authorize specific permissions through the original service.
The core problem OAuth solves is this: you want a third-party app to access your data on another service, but you do not want to give that app your password. Before OAuth, you would literally type your Google password into some random website hoping they would not steal it. OAuth creates a secure handshake where you authenticate directly with Google, approve specific permissions, and the app receives a limited-access token instead of your password.
OAuth 2.0 defines several “grant types” (flows) for different situations: the Authorization Code flow for web apps, Client Credentials for server-to-server communication, and others. Each flow is designed for specific security contexts. For example, browser-based apps cannot keep secrets, so they use PKCE (Proof Key for Code Exchange) to add security. Understanding which flow to use and when is crucial for building secure integrations.
Example
Social login everywhere: “Sign in with Google,” “Continue with Apple,” “Login with GitHub” - all use OAuth 2.0. The website never sees your Google/Apple/GitHub password. It just receives proof that you authenticated and gets access to whatever you approved (usually just your name and email).
Connecting apps to your accounts: When Zapier asks to connect to your Gmail to automate workflows, OAuth grants Zapier specific access (like reading certain labels) without giving Zapier your Gmail password. You can revoke this access anytime from your Google account settings.
Mobile app authentication: When you log into the Spotify mobile app, OAuth manages the authentication. The app receives tokens that let it access your playlists and preferences. If your phone is stolen, you can revoke those tokens from Spotify’s website without changing your password.
Third-party API access: When a developer builds an app that uses Twitter’s API to post tweets on users’ behalf, OAuth ensures users explicitly authorize that access. Users can see exactly what the app can do and revoke access anytime.
Analogy
The Valet Parking Key: Luxury cars have valet keys that start the engine but cannot open the trunk or glove box. When you give a valet your car, you give them limited access - they can park it but not access your private belongings. OAuth access tokens are like valet keys for your accounts - limited, specific, revocable access.
The Hotel Key Card: A hotel key card opens your room, maybe the gym and pool, but not other guests’ rooms or staff areas. And it expires when you check out. OAuth tokens work similarly - they grant specific access for a limited time, and you can “check out” (revoke) anytime.
The Power of Attorney (Limited): You might give someone limited power of attorney to handle specific legal matters on your behalf - sell this one property, sign this one document - without giving them control over your entire life. OAuth grants similarly limited authority to applications.
The Concert VIP Pass: A VIP pass gets you into specific areas - the VIP lounge, backstage - but not the production booth or the band’s dressing room. Each pass has specific permissions. OAuth scopes work like these pass levels, defining exactly what access each token provides.
Code Example
// OAuth 2.0 [Authorization Code Flow](https://reference.apios.info/terms/authorization-code-flow/) (most secure)
// 1. Redirect user to authorization server
const authUrl = new URL('https://oauth.provider.com/authorize');
authUrl.searchParams.append('response_type', 'code');
authUrl.searchParams.append('client_id', 'your_client_id');
authUrl.searchParams.append('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.append('scope', 'read:user read:email');
authUrl.searchParams.append('state', generateRandomState());
window.location.href = authUrl.toString();
// 2. Handle callback (server-side)
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
// Verify state parameter (CSRF protection)
if (state !== req.session.oauthState) {
return res.status(400).send('Invalid state');
}
// Exchange code for access token
const tokenResponse = await fetch('https://oauth.provider.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: 'your_client_id',
client_secret: process.env.CLIENT_SECRET,
redirect_uri: 'https://yourapp.com/callback'
})
});
const { access_token, refresh_token } = await tokenResponse.json();
// Use access token to call APIs
const userData = await fetch('https://api.provider.com/user', {
headers: { 'Authorization': `Bearer ${access_token}` }
});
});
Diagram
sequenceDiagram participant User participant App participant Auth participant API User->>App: Login request App->>Auth: Redirect to /authorize Auth->>User: Show consent User->>Auth: Approve Auth->>App: Authorization code App->>Auth: Exchange for tokens Auth->>App: Access + Refresh tokens App->>API: Request with Bearer token API->>App: Protected resource
Security Notes
CRITICAL: OAuth 2.0 is complex. Implement correctly following security best practices.
Flow Selection:
- Authorization Code: Web apps, default choice for user authentication
- Authorization Code + PKCE: Mobile/desktop apps, single-page apps
- Client Credentials: Machine-to-machine, no user involved
- Device Flow: Apps without browsers (IoT, smart TV)
- Never use Implicit: Deprecated, tokens exposed in URLs
Authorization Code Security:
- HTTPS mandatory: All OAuth endpoints require HTTPS
- Validate redirect_uri: Exact match, never allow wildcards or open redirects
- State parameter: Generate and validate state to prevent CSRF
- Code expiration: Authorization codes expire quickly (10 minutes)
- Code single-use: Authorization codes redeemable only once
PKCE (Proof Key for Code Exchange):
- Required for public clients: Mobile apps, SPAs must use PKCE
- Generate code_verifier: Client generates random code_verifier
- Create challenge: Hash code_verifier to create code_challenge
- Validate challenge: Server verifies challenge matches verifier
- Prevents authorization code theft: Even if code stolen, requires matching verifier
Token Management:
- Access token lifetime: Short-lived (15 minutes to 1 hour)
- Refresh token lifetime: Long-lived (days/weeks), stored securely
- Refresh token rotation: Issue new refresh token on each use
- Token revocation: Endpoint to revoke tokens immediately
- Token binding: Bind tokens to client to prevent token theft
Scope & Permissions:
- Minimal scopes: Request minimum required permissions
- Scope validation: Validate scopes match request permissions
- Scope restrictions: Don’t allow overly broad scopes
- Incremental consent: Request additional scopes incrementally
- Revoke access: Users can revoke app permissions
Token Endpoint Security:
- Client authentication: Verify client identity (client_secret or mTLS)
- Token endpoint protection: Protect token endpoint from abuse
- No tokens in URLs: Tokens sent in request body, not URL
- Rate limiting: Limit token requests per client
- Monitoring: Alert on unusual token requests
Common Vulnerabilities:
- Open redirect: Redirect_uri validation bypass
- Authorization code leakage: Code exposed in logs or URLs
- Token exposure: Tokens exposed in URLs or logs
- CSRF: Missing state parameter allows CSRF
- Access control bypass: Insufficient permission validation