@@ −14 +14 @@
## When NOT to use
−- Browser-only authentication with no API surface — use `auth-patterns` instead
+- Browser-only authentication with no API surface — use a browser-focused auth guide
- Network-level DDoS protection — use edge infrastructure (Cloudflare, Vercel, AWS Shield)
−- Full threat modeling — use `security-threat-model` instead
+- Full threat modeling — use a dedicated threat-modeling process
## Core concepts (updates)
−- OAuth 2.1: Consolidates and updates secure practices for OAuth deployments. Use the latest OAuth 2.1 draft as primary guidance (draft-ietf-oauth-v2-1, Feb–Mar 2026 work is active). Key enforced changes: deprecation of implicit and resource-owner-password credentials, PKCE required for public clients, and stronger defaults for redirects and client authentication. Source: IETF OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15
+- OAuth 2.1: use the IETF draft as the authoritative operational checklist. Current public revision: draft-ietf-oauth-v2-1-15 (Published 2 March 2026, expires 3 Sep 2026). Key enforced practices: deprecation of implicit and ROPC, PKCE required for public clients, exact redirect URI matching, stronger defaults for client authentication. Source: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15
- Sender-constrained tokens:
+ - mTLS: highest assurance for confidential client/server scenarios where certificate lifecycle can be managed.
+ - DPoP: RFC 9449 (proof-of-possession) binds tokens to client-generated keys and mitigates replay; servers must implement jti/nonce replay detection and reasonable token/key lifetimes.
− - mTLS (mutual TLS) is the strongest server-side option for confidential clients where you can manage client certificates.
+ - TLS-session-bound tokens: active IETF draft draft-mw-oauth-tls-session-bound-tokens-03 (last updated 2 Apr 2026) formalizes binding access tokens to TLS session parameters—follow the draft for deployment considerations and interoperability notes: https://datatracker.ietf.org/doc/draft-mw-oauth-tls-session-bound-tokens/03/
− - DPoP (Demonstrating Proof-of-Possession) is standardized (RFC 9449) and is appropriate where mTLS is not feasible; it binds the token to a client-generated key and mitigates token replay. Source: RFC 9449: https://datatracker.ietf.org/doc/rfc9449/
− - TLS-session-bound tokens are an active IETF draft (draft-mw-oauth-tls-session-bound-tokens-03, last updated 2026-04-02) that formalizes binding access tokens to TLS session parameters; follow the draft for deployment considerations and interoperability. Source: https://datatracker.ietf.org/doc/draft-mw-oauth-tls-session-bound-tokens/03/
−- JWT: Always verify signature and claims. Prefer asymmetric keys (RS/ES) and JWKS-based verification with caching and rotation. Enforce algorithm allowlist (never accept `alg: none`), verify iss/aud/exp/nbf, and apply a small clock-skew allowance (e.g., 30 seconds).
+- JWT: always verify structure, signature, and claims. Prefer asymmetric algorithms (RS/ES) validated via JWKS. Enforce algorithm allowlist (reject alg: none), validate iss/aud/exp/nbf, and allow a small clock skew (e.g., 30s).
−- PKCE: Required for public clients per OAuth 2.1. Generate the verifier client-side and send only the challenge to the authorization endpoint. Never transmit or store the PKCE verifier in URLs, the state parameter, or logs.
+- PKCE: required for public clients per OAuth 2.1. Use S256, high-entropy verifier, never transmit or log the verifier.
## Workflow (concise, copy-pasteable)
### Step 1 — JWT verification middleware
+- Use a maintained JOSE library (e.g., jose for Node, nimbus-jose-jwt for Java, pyjwt/jose for Python).
+- Verify in order: structure → signature → alg allowlist → iss/aud → exp/nbf → custom claims.
−- Use a maintained JOSE library (jose for Node, nimbus-jose-jwt for Java, pyjwt/jose for Python).
+- Remote JWKS: cache keys with short TTL, respect Cache-Control/Expires, implement exponential backoff on fetch failures. On key-rotation failures return 401 and surface a clear operator alert.
−- Verify in order: structure → signature → alg allowlist → iss/aud → exp/nbf → custom app claims.
−- For remote JWKS: use a short cache TTL, respect Cache-Control/Expires, and implement backoff on failures. If the key is rotated and verification fails, return 401 and log for rapid operator action.
Example (TypeScript pseudo):
const JWKS = createRemoteJWKSet(new URL(process.env.JWKS_URL!));
const { payload } = await jwtVerify(token, JWKS, { issuer, audience, algorithms: ['RS256'] });
−Notes: don't skip verification of 'alg'. Explicitly list allowed algorithms.
+Notes: explicitly list allowed algorithms and reject tokens that specify otherwise.
−### Step 2 — OAuth 2.1 & PKCE (operational guidance)
+### Step 2 — OAuth 2.1 & PKCE (operational)
−- Public clients (mobile, SPA) → Authorization Code flow + PKCE.
+- Public clients → Authorization Code + PKCE (S256).
- Confidential clients → Client Credentials or Authorization Code with client secret or mTLS.
−- Enforce redirect URI exact-match and a strict origin allowlist. Store and validate state nonces to prevent CSRF.
+- Enforce exact redirect URI matching and persistent, server-side state nonces (do not rely on client-supplied state-only validation).
−- PKCE details: use S256 challenge, high-entropy verifier, never reflect the verifier in state or logs.
−References: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15
+Reference: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-15
### Step 3 — Sender-constrained tokens deployment choices
+- mTLS: use when certificate management is feasible (service-to-service high assurance).
+- DPoP (RFC 9449): use where client-side key generation is practical; server must store short-window jti replay caches and bind tokens to DPoP keys.
−- Prefer mTLS for service-to-service when certificate management is feasible.
+- TLS-session-bound tokens (I-D v03): consider for deployments wanting server-side TLS binding; review interoperability implications before rollout. https://datatracker.ietf.org/doc/draft-mw-oauth-tls-session-bound-tokens/03/
−- Use DPoP (RFC 9449) for apps where client keys can be generated and attested. Ensure servers implement replay protections (jti reuse checks) and appropriate key lifecycle handling.
−- Monitor the TLS-session-bound tokens draft for server-side session binding approaches and interoperability notes: https://datatracker.ietf.org/doc/draft-mw-oauth-tls-session-bound-tokens/03/
### Step 4 — Rate limiting (practical)
+- Enforce broad limits at the edge (CDN/WAF) and fine-grained limits at the application (per-user, per-key).
+- Return standard rate-limit headers (Retry-After, X-RateLimit-Limit/Remaining/Reset).
−- Enforce edge (CDN/WAF) limits for broad DDoS/abuse and application-level limits for per-user or per-key granularity.
+- For serverless, use a durable counter store (Redis, Upstash, Vercel KV) or an edge provider capability. Avoid in-memory counters in horizontally scaled environments.
−- Return these headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
−- For serverless platforms, use a shared durable store (Redis, Upstash, Vercel KV) or an edge provider that supports rate limits; avoid in-memory counters for production.
### Step 5 — CORS (operational)
+- Use an explicit origin allowlist; do NOT use '*' when credentials are required.
−- Use explicit origin allowlist and do NOT use '*' when credentials are required.
+- Include CORS headers on error responses to prevent confusing client-side behavior.
−- Ensure error responses include appropriate CORS headers to avoid confusing client behavior.
### Step 6 — Webhook signature verification (hardened)
+- Prefer official SDKs/helpers from providers (Stripe, GitHub, Slack).
+- Require a timestamp header and reject requests older than an allowed window (default 5 minutes).
+- Require an event ID or idempotency key and persist recent IDs for replay detection.
−- Always verify using platform SDKs when available (Stripe, GitHub, Slack provide helpers).
+- Use timing-safe HMAC comparisons and rotate webhook secrets when supply-chain advisories affect your HTTP clients.
−- Require a timestamp header and reject requests older than a small window (default 5 minutes).
−- Require a unique event ID or idempotency key; persist recent IDs for replay detection and metric them.
−- Use timing-safe comparison for HMAC checks.
Response handling (examples):
- Missing signature → 400
- Timestamp skew > max_age → 400
- Signature invalid → 401
−- Duplicate event ID (replay) → 200 (idempotent) and log; or 409 if you must surface duplication.
+- Duplicate event ID (replay) → 200 (idempotent) and log; or 409 if business logic requires it.
### Step 7 — API keys & service-to-service auth
+- Generate opaque API keys, store only hashes, expose a prefix for lookup.