---
name: "OAuth 2.0 & OpenID Connect"
description: "Implement OAuth 2.0 and OIDC: Authorization Code + PKCE, Client Credentials, token management, refresh flows, security best practices, building your own OAuth provider, popular libraries (passport.js, authlib), and managed services (Auth0, Clerk, Keycloak)."
version: "1.0.0"
author: "skynet"
category: "dev"
agents: ["claude-code", "codex", "gemini"]
tags: ["oauth", "oidc", "authentication", "security", "pkce", "tokens"]
---

# OAuth 2.0 & OpenID Connect

---
name: "OAuth 2.0 & OpenID Connect"
description: "Implement OAuth 2.0 and OIDC: Authorization Code + PKCE, Client Credentials, token management, refresh flows, security best practices, building your own OAuth provider, popular libraries (passport.js,"
version: "1.0.0"
author: "skynet"
category: "dev"
tags: ["oauth", "oidc", "authentication", "security", "pkce", "tokens"]
---

I will start by checking the knowledge graph for any existing notes on OAuth 2.0 or OpenID Connect to ensure consistency and leverage any previously stored insights. call mcp_brain_rah_search_nodes(query="OAuth OIDC security")

### OAuth 2.0 & OIDC: The SaaS Security Reference

#### 1. OAuth 2.0 Flows: Strategic Selection
OAuth 2.0 is a framework of "grants" designed for different trust models.

| Flow | Primary Use Case | Trust Level | Security Requirement |
| :--- | :--- | :--- | :--- |
| **Auth Code + PKCE** | **Web/Mobile/SPA.** The standard for user-facing apps. | Medium/High | **PKCE is mandatory.** |
| **Client Credentials** | **M2M (Machine-to-Machine).** Service A → Service B. | High (Server) | Client Secret must be in a Vault. |
| **Device Code** | **CLIs, Smart TVs, IoT.** Input-constrained devices. | Medium | User approves via secondary device. |
| **Refresh Token** | **Session persistence.** Silent re-authentication. | High | Must be rotated and revoked on reuse. |

---

#### 2. Core Implementation: Authorization Code + PKCE
**PKCE (Proof Key for Code Exchange)** is required for all clients to prevent authorization code injection.

1.  **Generate PKCE Pair:**
    *   `code_verifier`: Cryptographically random string (43–128 chars).
    *   `code_challenge`: `Base64URL(SHA256(code_verifier))`.
2.  **Authorization URL:** Include `state` (CSRF protection), `code_challenge`, and `code_challenge_method=S256`.
3.  **Token Exchange:** Send the original `code_verifier` to the `/token` endpoint. The server hashes it and compares it to the previously stored challenge.

**Token Storage Decision:**
*   **Server-Side:** Use encrypted **HttpOnly, Secure, SameSite=Lax** cookies.
*   **SPA/Frontend:** Do not use `localStorage` (XSS risk). Use a **BFF (Backend-for-Frontend)** pattern to manage tokens server-side.

---

#### 3. Token Management & Lifecycles
*   **Access Tokens (AT):** Short-lived (15m–1hr). Should be JWTs if using stateless validation.
*   **Refresh Tokens (RT):** Long-lived.
    *   **Rotation:** Issue a new RT on every use; invalidate the old one.
    *   **Revocation:** Provide a `/revoke` endpoint for user logout or security breaches.
    *   **Sliding Expiration:** Extend RT lifetime on activity, but set an absolute "Max Age" (e.g., 30 days).

---

#### 4. OpenID Connect (OIDC): Identity Layer
OIDC adds identity to OAuth.
*   **ID Token:** A JWT containing `sub` (unique ID), `email`, and `name`. **Validate the signature (RS256) locally.**
*   **Discovery:** Use the `/.well-known/openid-configuration` endpoint to find JWKS, token, and auth endpoints.
*   **Nonce:** Use to prevent replay attacks by binding the ID token to the original request.

---

#### 5. Security Checklist
*   **Redirect URI Validation:** Use strict string matching. **No wildcards.**
*   **DPoP (Demonstrating Proof-of-Possession):** Binds tokens to a private key held by the client, neutralizing stolen bearer tokens.
*   **HTTPS:** Mandatory for all redirects and endpoints.
*   **CORS:** Restrict token endpoints to your specific frontend domains.

---

#### 6. Building Your Own OAuth Provider
If your SaaS exposes an API to 3rd party developers:
*   **Scopes:** Use granular permissions (e.g., `reports:read`, `settings:write`).
*   **Consent:** Build a clear UI showing exactly what data the developer is requesting.
*   **Client Management:** Allow developers to cycle secrets and define allowed redirect URIs.

---

#### 7. Modern Ecosystem
*   **Libraries:**
    *   **Node.js:** `Arctic` (minimalist), `Auth.js` (Next.js/React), `Lucia` (Session focus).
    *   **Python:** `Authlib` (comprehensive), `PyOIDC`.
    *   **Java:** `Spring Security OAuth2`.
*   **Managed Services (Buy vs Build):**
    *   **Buy:** *Clerk, Auth0, Supabase Auth.* High speed-to-market, handles MFA/Security.
    *   **Build:** *Keycloak, Ory Hydra, FusionAuth.* High control, data residency compliance.

---

#### 8. Common Mistakes (Anti-Patterns)
*   **Implicit Flow:** **Deprecated.** Use Auth Code + PKCE instead.
*   **Infinite Lifetimes:** Never issue tokens that don't expire.
*   **JWT as Session:** Storing sensitive, mutable data in JWTs is risky; use them for stateless auth only.
*   **Missing State:** Failing to validate the `state` parameter leads to Login CSRF.

---

#### 9. Code Examples: Auth Code + PKCE

**Node.js (using `arctic`)**
```javascript
import { GitHub, generateState, generateCodeVerifier } from "arctic";

// 1. Redirect to Auth Provider
const state = generateState();
const codeVerifier = generateCodeVerifier();
const url = await github.createAuthorizationURL(state, codeVerifier, {
    scopes: ["user:email"]
});
// STORE state & codeVerifier in an HttpOnly session cookie
res.appendHeader("Set-Cookie", `state=${state}; HttpOnly; Secure`);
res.redirect(url.toString());

// 2. Callback Handling
const code = req.query.code;
const storedState = req.cookies.state;
if (req.query.state !== storedState) throw new Error("CSRF Error");

const tokens = await github.validateAuthorizationCode(code, codeVerifier);
const accessToken = tokens.accessToken();
```

**Python (using `Authlib` + FastAPI)**
```python
from authlib.integrations.starlette_client import OAuth
from fastapi import FastAPI, Request

oauth = OAuth()
oauth.register(
    name='google',
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'}
)

@app.get('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth_callback')
    # Authlib handles PKCE and State generation automatically
    return await oauth.google.authorize_redirect(request, redirect_uri)

@app.get('/callback')
async def auth_callback(request: Request):
    token = await oauth.google.authorize_access_token(request)
    user = token.get('userinfo')
    return {"user": user, "at": token['access_token']}
```

I'd add this as: **OAuth 2.0 & OIDC Technical Reference** in **security, architecture** — want me to?

