OAuth Pushed Authorization Requests for CDN API Gateway Security

· James Thornton · 11 min read

Traditional OAuth 2.0 authorization requests pass all parameters through the browser as URL query strings. The client constructs a long URL containing the client_id, scope, redirect_uri, state, nonce, and PKCE challenge, then redirects the user's browser to that URL. Every intermediary — the browser, browser extensions, HTTP logs, and referrer headers — can see and potentially modify these parameters. Pushed Authorization Requests (PAR), defined in RFC 9126, eliminate this exposure by moving the authorization parameters to a secure back-channel between the client and the authorization server.

The Problem PAR Solves

OAuth authorization URLs carry sensitive information. The redirect_uri tells an attacker where tokens will be delivered. The scope reveals what access the client is requesting. The state parameter, while designed as a CSRF token, can leak session information if poorly constructed. The PKCE code_challenge is intentionally public, but the full URL including all parameters creates a fingerprint of the authorization request that aids phishing attacks.

Browser-based parameter passing also creates practical problems for complex authorization requests. Financial-grade APIs require rich authorization details — transaction amounts, account identifiers, consent references — that exceed URL length limits in some browsers and proxy servers. Rich Authorization Requests (RAR, RFC 9396) add structured authorization details that further increase URL length.

PAR addresses both security and practical concerns by moving the parameters off the URL entirely. The client sends parameters directly to the authorization server's PAR endpoint via an authenticated POST request. The server responds with a request_uri — a short, opaque reference. The client redirects the browser using only this request_uri, keeping the authorization parameters confidential.

PAR Flow Architecture

Step 1: Push Authorization Parameters

The client authenticates to the PAR endpoint (using client_secret_post, client_secret_basic, private_key_jwt, or client certificate authentication) and sends all authorization parameters as a POST body. The request includes the same parameters that would normally appear in the authorization URL: response_type, client_id, scope, redirect_uri, state, nonce, code_challenge, and code_challenge_method.

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

The authorization server validates all parameters, verifies client authentication, stores the parameters internally, and returns a JSON response containing the request_uri (an opaque reference like urn:ietf:params:oauth:request_uri:abc123) and an expires_in value (how long the request_uri is valid, typically 60–600 seconds).

Step 2: Browser Redirect

The client redirects the user's browser to the authorization endpoint with only the client_id and request_uri. The full URL is short and contains no sensitive parameters:

https://auth.example.com/authorize?client_id=app123&request_uri=urn:ietf:params:oauth:request_uri:abc123

The authorization server resolves the request_uri to retrieve the stored parameters, validates that the client_id in the URL matches the client that created the request_uri, and proceeds with the authorization flow (user authentication, consent screen, code issuance) using the stored parameters.

Step 3: Authorization Code Exchange

The remainder of the flow is standard OAuth with PKCE. The authorization server redirects back to the client's redirect_uri with an authorization code. The client exchanges the code for tokens at the token endpoint. The PAR flow does not change the token exchange — it only changes how the authorization request parameters are transmitted.

PAR Flow Through CDN Infrastructure Client App CDN Edge Auth Server Browser 1. POST /par + client auth + params request_uri 2. Redirect: /authorize?request_uri=... 3. User authenticates 4. POST /token code + code_verifier 5. access_token + refresh_token
Figure 1: Pushed Authorization Request flow through CDN — authorization parameters travel server-to-server (Step 1), not through the browser.

CDN Edge Integration with PAR

CDN edge infrastructure interacts with PAR at two critical points: the PAR endpoint (where the client pushes parameters) and the authorization redirect (where the browser presents the request_uri).

PAR Endpoint at CDN Edge

The PAR endpoint receives authenticated POST requests from OAuth clients. The CDN edge worker can provide several security functions at this endpoint:

request_uri Resolution at CDN Edge

When the browser arrives at the authorization endpoint with a request_uri, the CDN edge can pre-validate the URI before forwarding to the authorization server. The edge worker checks that the request_uri format is valid (matches the urn:ietf:params:oauth:request_uri: prefix), the URI has not expired (by checking a TTL entry in edge KV), and the URI has not already been consumed (by checking a consumed flag in edge KV).

This edge-level validation provides immediate rejection of invalid or expired request_uri values without an origin round-trip. The edge worker can return a user-friendly error page explaining that the authorization link has expired and suggesting the user restart the flow.

request_uri Lifecycle Management

The request_uri is a single-use, time-limited reference. Its lifecycle must be strictly managed to prevent replay attacks and unauthorized parameter access.

Creation and Storage

When the PAR endpoint processes a valid request, it generates a request_uri with sufficient entropy (128+ bits) to prevent guessing. The authorization parameters are stored alongside the URI in the authorization server's database and replicated to edge KV for fast resolution. The KV entry includes the parameters, the creating client's ID, the creation timestamp, and a consumed flag (initially false).

Consumption

When the authorization endpoint resolves a request_uri, it marks the URI as consumed atomically. Any subsequent attempt to use the same URI is rejected. In edge KV, this requires an atomic compare-and-swap operation (if the platform supports it) or a separate consumed-URIs set that is checked before resolution.

The single-use requirement is a security control against replay attacks. Without it, an attacker who intercepts the browser redirect URL could replay the request_uri in their own browser to initiate an authorization flow with the victim's parameters. The single-use constraint ensures that the request_uri can only be used by the intended browser session.

Expiration

The request_uri expires after the expires_in period (typically 60–600 seconds). Edge KV entries are created with a TTL matching this period, ensuring automatic cleanup. The short TTL limits the window for replay attacks even if the single-use check fails due to replication lag.

PAR and FAPI 2.0 Compliance

FAPI 2.0 (Financial-grade API Security Profile) mandates either PAR or JAR (JWT-Secured Authorization Requests, RFC 9101) for authorization requests. PAR is the more commonly implemented choice because it is simpler — JAR requires the client to construct, sign, and potentially encrypt a JWT containing the authorization parameters, which adds cryptographic complexity.

FAPI 2.0's PAR requirements include mandatory client authentication on the PAR endpoint (no public clients), request_uri single-use enforcement, short request_uri TTL (FAPI recommends 60 seconds), and binding between the PAR client and the authorization request (the client_id in the authorization URL must match the client that created the request_uri).

For CDN gateways serving financial services APIs, the edge worker must enforce these requirements: rejecting PAR requests without client authentication, validating request_uri TTL and single-use at the edge, and verifying client-URI binding on the authorization redirect. The edge provides these checks at lower latency than the origin authorization server, improving the user experience for financial authorization flows.

PAR Security Properties at CDN Edge Parameter Confidentiality Params sent back-channel Not in browser URL/logs Not in Referer headers Client Authentication PAR endpoint requires auth Proves client identity Blocks unauthorized pushes Replay Prevention request_uri single-use Short TTL (60-600s) Consumed flag in edge KV Tamper Resistance Params stored server-side Can't be modified by browser/extensions All four properties enforced at CDN edge — no origin round-trip for validation failures
Figure 2: PAR's four security properties, all enforceable at CDN edge for low-latency rejection of invalid requests.

PAR vs JAR: Choosing for CDN Architecture

PAR and JAR (JWT-Secured Authorization Requests) both solve the problem of securing authorization parameters. JAR encodes the parameters in a signed (and optionally encrypted) JWT that the client includes in the authorization URL as a request parameter. The authorization server validates the JWT signature and extracts the parameters.

For CDN architectures, PAR is generally preferred because the authorization parameters are stored server-side (not in the URL, avoiding length limits), the CDN edge does not need to validate JWT signatures (simpler edge worker implementation), the request_uri is short and fixed-format (easier to cache and validate at edge), and parameter updates do not require reissuing JWTs (server-side storage can be modified before the URI is consumed, enabling dynamic consent adjustments).

JAR is preferred when the authorization server does not support PAR (PAR is newer, RFC 9126 published in 2022), when the client needs to prove the authorization request was not modified since creation (the JWT signature provides non-repudiation that PAR does not), or when the architecture requires offline-verifiable authorization requests (the JWT can be validated without contacting the authorization server's storage).

Implementation Considerations for CDN Gateway

CDN edge workers implementing PAR support should handle several edge cases. The request_uri namespace must be distinct from other URIs the authorization server handles — the urn:ietf:params:oauth:request_uri: prefix is the standard namespace. The edge worker should reject any request_uri that does not match this prefix to prevent confusion attacks.

Clock synchronization between the CDN edge and the authorization server affects request_uri TTL enforcement. If the edge's clock is ahead of the authorization server's clock, the edge may reject a valid request_uri as expired. CDN edge workers should apply a small grace period (5–10 seconds) to TTL checks to accommodate clock skew across the distributed infrastructure.

Error handling for expired or consumed request_uri values should provide a user-friendly experience. Rather than a raw HTTP error, the CDN edge should serve a branded error page explaining that the authorization link has expired, with a button to restart the flow. This page should be served from the CDN cache to ensure fast loading even during authorization server outages.

For CDN architectures using multiple CDN providers, the request_uri state must be accessible from all CDN edges. If using edge KV, the KV store must be globally distributed. If using a centralized authorization server database, all CDN edges must be able to query it with acceptable latency. A hybrid approach stores the consumed flag in edge KV (for fast single-use enforcement) and falls back to the authorization server for parameter retrieval (for correctness during edge KV replication lag).

External References

References & Standards: W3C Web Performance · OWASP CDN Security