Guide
Premium
Intermediate
Real Projects

OAuth 2.1 in Production: Mandatory PKCE, Refresh Token Rotation, DPoP, and Token Exchange Across Service Chains

A practical guide to the protocol almost everyone integrates by copying an example and almost nobody audits: what OAuth 2.1 changes versus OAuth 2.0 and why it isn't cosmetic, PKCE explained from the attack it prevents —authorization code injection— including the downgrade trap that leaves the flow defenseless even when the client implements it correctly, exact redirect_uri matching and why a prefix check is a compromised account, RFC 9207's iss parameter against the mix-up attack, refresh token rotation with family-based reuse detection, including the race condition that logs out legitimate users and the grace window that fixes it, DPoP (RFC 9449) with the proof JWT, the cnf.jkt confirmation, the ath claim, server-issued nonces, and the shared jti cache that makes replay protection real, and token exchange (RFC 8693) for delegation without impersonation using the nested act claim, downscoping, and narrowed audiences. Covers discovery with RFC 8414 and RFC 9728 —the foundation of MCP authorization—, RFC 8707 resource indicators, an honest DPoP versus mTLS comparison, eight recurring mistakes, a production checklist, FAQ, and glossary. With production-ready code in Python, TypeScript, and SQL. 22 September 2026 update: the missing link, the resource server, with the five checks on an access token and the two almost nobody performs (audience and authorization), algorithm confusion with alg:none and RS256 downgraded to HS256 using as the secret the public key the attacker already has, a JWKS cache with a double limit that neither gets stuck after a rotation nor lets a made-up kid become a DoS against the IdP, the at+jwt type from RFC 9068 and why an API that accepts ID tokens is accepting anyone signed in to any application in the tenant, and the choice between local validation and introspection framed as what it really is: a revocation decision, not a performance one. Really logging out, with the honest answer on how long a revoked token lives (until its exp) and the access token lifetime understood as your revocation window, what RFC 7009 actually revokes and why it returns 200 even for tokens that never existed, back-channel logout as the only variant that survives third-party cookie blocking with the three checks specific to a logout token and the sid that saves you from signing everyone out, and a bounded Redis denylist whose entries expire exactly when the token does. And browser applications, with the localStorage/memory/cookie comparison reframed around blast radius, a complete BFF in FastAPI with PKCE, cookie-bound state, tokens that never cross into the browser and a proxy with an origin check, plus the bill the BFF charges: server state, CSRF back on the table, and the SSRF that appears if you don't validate which paths get forwarded. Grounded in RFC 10017 and RFC 9700. September 23, 2026 expansion: client authentication with private_key_jwt and the audience injection vulnerability fixed by draft-ietf-oauth-rfc7523bis (aud equal to the issuer, never the token endpoint, plus the client-authentication+jwt typ), strict server-side validation with a jti cache and zero-downtime key rotation; PAR (RFC 9126) with the correct assertion, require_pushed_authorization_requests and how it differs from JAR; step-up with RFC 9470, acr, auth_time and the max_age that is actually enforceable; native apps and CLIs with 127.0.0.1 loopback per RFC 8252, and device flow as a phishing vector with its mitigations; adversarial tests in pytest; and Prometheus metrics and alerts to detect token theft before the incident.

55 minutes read
Josué Puig
2 views

Verificando acceso...

Loading comments...

Related Resources

Guía
PREMIUM

API Versioning and Contract Testing: Safe Changes, OpenAPI in CI, Pact, and Retiring Endpoints with Sunset

A practical guide to changing your APIs without breaking the people who consume them: why compatibility rules invert between the request and the response —and why widening a returned enum breaks clients even though you are "only adding"—, the tolerant reader pattern in Pydantic with an escape hatch and a metric, OpenAPI generated from the code and diffed on every pull request with oasdiff (including the git diff --exit-code step without which the whole check is theatre), consumer-driven contract testing with Pact: type matchers instead of literal values, well-designed provider states, version selection with deployed_or_released, and the gate that actually makes it safe, can-i-deploy paired with record-deployment. It also covers rolling this out without stopping the factory using pending and WIP pacts, bi-directional contracts when the provider is a third party, the three versioning strategies with their real operational costs, why versioning the whole API for a single endpoint guarantees nobody migrates, retiring versions with the Deprecation (RFC 9745) and Sunset (RFC 8594) headers plus the migration Link, the per-consumer metric without which no sunset date is ever met, brownouts returning 410 Gone before the final shutdown, and the BACKWARD, FORWARD and FULL compatibility modes for event schemas. With production-ready code in Python, YAML, Bash and PromQL, eight recurring mistakes, a production checklist, FAQ and glossary. It also extends the contract beyond the happy path: errors with RFC 9457 (problem+json), cursor pagination and defaults as part of the contract, the expand/contract pattern for renaming a field across database and API with no maintenance window, governance with Spectral, buf breaking for gRPC and Protobuf, GraphQL schema evolution with @deprecated and real per-field usage, and semantic versioning of generated SDKs. It also covers the contracts that never show up in the schema and break just as hard: outbound webhooks with the version pinned on the subscription, HMAC signing with a timestamp window and key rotation, Idempotency-Key for safe POST retries, the RateLimit and RateLimit-Policy headers —and why lowering a limit is a breaking change—, and OAuth scopes, the blind spot no OpenAPI diff will ever catch.

Guía
PREMIUM

asyncio in Production: Never Block the Event Loop — TaskGroups, Cancellation and Bounded Concurrency

A practical asyncio guide for Python services in production: why blocking the event loop degrades the whole process without raising a single exception, how to catch it by measuring loop lag and with Python 3.14 introspection, structured concurrency with TaskGroup and handling ExceptionGroup via except*, the task the garbage collector makes vanish, timeouts with a deadline budget propagated across services, correct cancellation with cleanup and shield, bounded concurrency with semaphores and backpressured queues, synchronization primitives, and what changes with eager tasks, python -m asyncio pstree and free-threading. With production-ready code and a deployment checklist.

Guía
PREMIUM

Cache-Aside in Production: TTLs, Invalidation, and How to Prevent Cache Stampedes

The complete guide to the cache-aside pattern with Redis: jittered TTLs, correct invalidation, and the three defenses against cache stampedes (distributed lock, single-flight, and XFetch). Expanded with stale-while-revalidate, fail-open and circuit breakers, two-tier caching with RESP3 invalidation, delayed double delete and CDC, hot keys, eviction and memory management, observability with Prometheus, testing, choosing an engine (Redis, Valkey, Memcached), and a complete TypeScript implementation. With production-ready code in Python and TypeScript.