PKCE Authorization Flow at the CDN Proxy Layer

· Sarah Mitchell · 11 min read

When CDN edge servers act as authentication proxies — handling OAuth authorization code flows on behalf of backend applications — the authorization code travels through infrastructure that the application developer does not control. That code transits edge servers, reverse proxies, and load balancers before reaching the token exchange endpoint. PKCE (Proof Key for Code Exchange, defined in RFC 7636) eliminates the authorization code interception attack that this architecture enables by cryptographically binding the code to the client that initiated the flow. For CDN operators building edge authentication systems, PKCE is not optional — it is the minimum bar for secure authorization code flows through proxy infrastructure.

The Authorization Code Interception Problem at CDN Edge

The OAuth 2.0 authorization code flow involves a redirect from the authorization server back to the client application, carrying an authorization code in the URL query string. The client then exchanges this code for access and refresh tokens at the token endpoint. The vulnerability lies in the redirect step: if an attacker can intercept the authorization code before the legitimate client receives it, they can exchange it for tokens.

In traditional single-server deployments, the redirect goes directly from the browser to the application server over TLS, making interception difficult. CDN proxy architectures introduce additional points where the code is exposed:

Without PKCE, an attacker who obtains the authorization code from any of these points can exchange it for tokens using only the client_id (which is public for single-page applications) and the redirect_uri (which is predictable). PKCE makes the stolen code worthless by requiring a secret that only the legitimate client knows.

PKCE Flow Through CDN Proxy Architecture Browser User agent CDN Edge Proxy Generate verifier Store in edge KV Auth Server Store challenge Origin App Receives tokens Step 1 login Step 2 challenge Edge Callback Retrieve verifier from edge KV auth code (exposed!) Token Endpoint Verify S256 code + verifier Attacker: has code, no verifier Cannot exchange → blocked
Figure 1: PKCE flow through CDN proxy — the edge generates and stores the code_verifier, sends only the code_challenge to the auth server, and uses the verifier during token exchange. An attacker who intercepts the authorization code lacks the verifier.

PKCE Mechanics: Code Verifier and Code Challenge

PKCE operates on a simple cryptographic principle: the client creates a secret (code_verifier), derives a non-reversible challenge from it (code_challenge), sends the challenge with the authorization request, and proves knowledge of the original secret during the token exchange.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages

Code Verifier Generation

The code_verifier is a high-entropy random string between 43 and 128 characters, using the unreserved character set (A-Z, a-z, 0-9, hyphen, period, underscore, tilde). In CDN edge worker environments, the verifier must be generated using a cryptographically secure random number generator — the Web Crypto API's crypto.getRandomValues() is available in all major edge runtimes (Cloudflare Workers, Fastly Compute, Deno Deploy).

A critical implementation detail for CDN deployments: the code_verifier must be stored securely and associated with the user's session. In edge architectures, this means writing the verifier to edge KV storage with a session identifier as the key. The verifier must survive the time between the authorization redirect (when it is generated) and the callback (when it is needed), which can be seconds to minutes depending on user interaction with the identity provider.

S256 Code Challenge Transform

The S256 transform computes the SHA-256 hash of the ASCII representation of the code_verifier, then base64url encodes the result. This one-way transform means the code_challenge reveals nothing about the code_verifier. Even if an attacker observes the code_challenge in the authorization request (which travels through the browser's address bar), they cannot derive the code_verifier needed for the token exchange.

// S256 transform at CDN edge worker
code_challenge = BASE64URL(SHA256(ASCII(code_verifier)))

// Example:
// code_verifier:  "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
// SHA-256 hash:   [19, 211, 30, 150, ...]
// code_challenge: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"

Edge-Terminated Authentication with PKCE

In a CDN edge-terminated authentication architecture, the edge server handles the entire OAuth flow — it initiates the authorization redirect, receives the callback, exchanges the code for tokens, and manages the session. The backend application never sees authorization codes or performs token exchanges. This pattern, sometimes called the Backend-for-Frontend approach, centralizes authentication logic at the CDN edge.

Step 1: Authorization Initiation at Edge

When an unauthenticated request arrives at the CDN edge, the edge worker generates the PKCE parameters, stores the code_verifier in edge KV, and redirects the browser to the authorization endpoint with the code_challenge. The edge worker also generates a state parameter to prevent CSRF attacks and stores it alongside the code_verifier.

Step 2: Authorization Callback at Edge

The authorization server redirects the browser back to the callback URL, which resolves to the CDN edge server. The edge worker receives the authorization code and state parameter, validates the state against the stored value, retrieves the code_verifier from edge KV, and makes a server-to-server request to the token endpoint with the authorization code and code_verifier.

This server-to-server token exchange is critical for CDN security. The edge worker calls the token endpoint directly, not through the browser, so the tokens never appear in browser history, URL bars, or CDN logs. The exchange uses the edge server's own TLS connection to the authorization server, separate from the client-facing TLS termination.

Step 3: Session Establishment at Edge

After receiving the tokens, the edge worker stores them in edge KV (encrypted, keyed by a session identifier), sets a secure HTTP-only cookie with the session identifier on the response, and cleans up the temporary PKCE state. Subsequent requests present the session cookie, and the edge worker retrieves the tokens from KV to authorize requests to the origin server.

Edge-Terminated PKCE Authentication Lifecycle Edge Worker Gen verifier Store to KV Redirect Recv callback Exchange code Edge KV verifier + state Auth Server Validates S256 Origin App Never sees code challenge + state code + verifier
Figure 2: Edge-terminated PKCE lifecycle — the edge worker manages the entire flow, from verifier generation through token exchange, keeping PKCE state in edge KV and tokens out of the browser.

CDN-Specific PKCE Challenges

Edge KV Consistency for Verifier Storage

The code_verifier is written to edge KV during the authorization initiation and read during the callback, potentially milliseconds to minutes later. CDN edge KV stores often provide eventual consistency rather than strong consistency, meaning a write at one PoP may not be immediately visible at another PoP.

If the authorization callback arrives at a different PoP than the one that initiated the flow (due to routing changes, anycast path shifts, or DNS propagation delays), the code_verifier may not be available. CDN architectures address this through several strategies:

Redirect URI Configuration with CDN Domains

CDN architectures may use multiple domain names for the same application — the vanity domain (app.example.com), the CDN domain (example.cdn-provider.net), and potentially regional domains for geo-restricted markets. Each domain that could receive the authorization callback must be registered as a valid redirect_uri with the authorization server.

A common CDN-specific issue arises when the authorization redirect uses one domain but the callback arrives at a different domain due to CDN routing decisions. The authorization server rejects the token exchange if the redirect_uri does not match exactly. The solution is to use a single, consistent callback domain that all CDN entry points redirect through — typically the primary vanity domain with a dedicated callback path like /auth/callback.

PKCE with CDN Caching

Authorization redirects and callbacks must never be cached by the CDN. The redirect response is unique per session (containing a unique state parameter and code_challenge), and the callback URL contains a one-time-use authorization code. Caching either would result in session fixation attacks or authorization code reuse.

CDN caching rules must explicitly exclude the authentication paths from caching. The Cache-Control headers on authentication endpoints should include no-store, no-cache, must-revalidate. Additionally, the CDN should be configured to not cache responses with Set-Cookie headers, which the authentication flow uses to establish sessions.

PKCE for Public Clients vs Confidential Clients at CDN Edge

OAuth 2.0 distinguishes between public clients (which cannot securely store a client secret, like browser SPAs) and confidential clients (which can, like server-side applications). CDN edge workers occupy an interesting middle ground — they are server-side code that can store secrets, but they run in a shared multi-tenant environment where secret isolation depends on the CDN platform's security guarantees.

For CDN edge-terminated authentication, the edge worker acts as a confidential client. It stores the client_secret in encrypted configuration, uses it during the token exchange, and combines it with PKCE for defense in depth. The client_secret authenticates the client to the authorization server, while PKCE ensures the authorization code is bound to the specific edge session that initiated the flow.

This combination is particularly important because CDN edge workers handle requests from all users. Without PKCE, a malicious user who intercepts another user's authorization code could potentially exchange it using the same edge worker (which has access to the shared client_secret). PKCE prevents this because each authorization flow has a unique code_verifier that is session-specific.

PKCE in OAuth 2.1 and Future CDN Implications

The OAuth 2.1 draft specification makes PKCE mandatory for all authorization code flows, regardless of client type. The plain code challenge method is removed entirely, and only S256 is permitted. For CDN operators, this means:

The OAuth 2.1 specification also introduces additional security requirements that affect CDN deployments: exact redirect_uri matching (no pattern matching), refresh token rotation or sender-constraining, and the elimination of the implicit grant. CDN edge authentication architectures that adopt these requirements now will be forward-compatible with OAuth 2.1 compliant authorization servers as they roll out across the identity ecosystem.

Testing PKCE Implementation in CDN Edge Workers

Testing PKCE in CDN environments requires verifying the cryptographic operations, the KV storage lifecycle, and the end-to-end flow across the CDN infrastructure.

Unit testing the S256 transform: Verify the code_challenge computation using known test vectors from RFC 7636 Appendix B. The test vector uses dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk as the code_verifier and expects E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM as the code_challenge.

Integration testing KV lifecycle: Test that the code_verifier is correctly stored during initiation and retrieved during callback, including scenarios where the callback arrives at a different PoP. CDN testing strategies should include simulating PoP failover during the PKCE flow.

Security testing: Verify that authorization codes cannot be exchanged without the correct code_verifier, that the plain method is rejected, that code_verifiers with insufficient entropy are rejected, and that expired code_verifiers (from abandoned authentication flows) are cleaned up from edge KV to prevent storage leaks.

Monitoring should track PKCE validation failure rates across PoPs. A spike in invalid_grant errors correlated with PKCE failures may indicate an attack in progress, a misconfigured authorization server, or KV consistency issues in specific CDN regions. CDN observability platforms should create alerts for PKCE failure rates exceeding the baseline, broken down by PoP and authorization server.

PKCE and Token Binding: Layered Protection

PKCE and DPoP token binding address different attack vectors in CDN authentication architecture. PKCE protects the authorization code exchange phase, ensuring that stolen authorization codes cannot be exchanged for tokens. DPoP protects the token usage phase, ensuring that stolen access tokens cannot be used by unauthorized parties. Deploying both in a CDN edge authentication architecture provides end-to-end sender-constraining: the authorization code is bound to the client via PKCE, and the resulting tokens are bound to the client via DPoP.

This layered approach is particularly valuable in CDN architectures where different security boundaries apply at different stages of the authentication lifecycle. The authorization code transits the browser and CDN request path, while access tokens live in edge storage and transit the edge-to-origin connection. Each mechanism protects its respective stage of the token lifecycle, and together they eliminate the two primary attack vectors in CDN-proxied authentication: code interception and token theft.

External References

References & Standards: RFC 7234 · W3C Web Performance