Skip to content

Authorization requests are easy to underestimate because they happen before the token exists.

In a conventional authorization-code flow, the application sends a long redirect through the browser. That URL can carry redirect_uri, scope, state, nonce, PKCE parameters, resource indicators, claims requests, and sometimes other domain-specific context. The browser is the right place for user interaction, but it is not a great place to carry every security-relevant detail of a high-value authorization request.

The practical problems are familiar: long URLs, request details in browser history and logs, parameters moving through a front channel, and the risk that a changed request still looks syntactically valid. RFC 9126 standardizes Pushed Authorization Requests (PAR) to move the rich request to a direct client-to-authorization-server call. RFC 9101 standardizes JWT-Secured Authorization Requests (JAR) so the request parameters can be signed, and optionally encrypted, as a request object.

In the ProAuth v3 preview, these two features become part of the hardened client toolkit for high-assurance OIDC and OAuth integrations.

PAR changes where the request travels

PAR does not remove the browser from the authorization flow. It changes what the browser has to carry.

flowchart LR
    subgraph Before["Before PAR: rich request in the browser front channel"]
        AppBefore["Client application"]
        BrowserBefore["Browser redirect URL\nresponse_type, scope, redirect_uri, state, nonce, PKCE, resource"]
        AuthBefore["Authorization server"]
        Exposure["History, logs, referrers,\nand tampering surface"]

        AppBefore --> BrowserBefore
        BrowserBefore --> AuthBefore
        BrowserBefore --> Exposure
    end

    subgraph After["After PAR: rich request pushed over the back channel"]
        AppAfter["Client application"]
        ParEndpoint["ProAuth PAR endpoint\nPOST /connect/par"]
        RequestUri["Short-lived one-time request_uri"]
        BrowserAfter["Browser redirect URL\nclient_id + request_uri"]
        AuthAfter["Authorization server resolves\nstored request server-side"]

        AppAfter -->|"Client-authenticated POST\nwith request details"| ParEndpoint
        ParEndpoint --> RequestUri
        RequestUri --> BrowserAfter
        BrowserAfter --> AuthAfter
    end

With PAR, the client first sends the authorization request parameters directly to ProAuth at POST /connect/par, or to the tenant-specific POST /{tenantKey}/connect/par endpoint. ProAuth validates and stores the pushed request, then returns a request_uri with an expiry. The browser redirect that follows is compact: it carries the client_id and the returned request_uri, not the full set of authorization parameters.

That is the important design move. The authorization server can authenticate the client and validate the request before user interaction starts. The browser still takes the user to the authorization endpoint, but it no longer transports the complete authorization request.

The ProAuth v3 PAR documentation describes the default request URI lifetime as 00:01:30. Expired or replayed pushed request URNs fail with invalid_request_uri, and consumption is protected so concurrent retries cannot redeem the same pushed request more than once.

JAR changes what the request can say

PAR protects where the request travels. JAR protects the request content.

With JAR, the client puts authorization request parameters into a JWT request object. The request object is signed, and may also be encrypted. ProAuth validates the request object before continuing the authorization flow, including the issuer, audience, expiry, signature, client identity, and configured client signing metadata.

That matters when the request itself carries business or security meaning. A changed redirect_uri, broader scope, different resource, or altered claims request should not drift through the flow as an ordinary query-string edit. JAR gives ProAuth a cryptographic way to reject a request whose signed content no longer matches what the client issued.

The ProAuth v3 preview accepts inline JAR through the request authorization parameter. Remote JAR uses request_uri, and the URI must be registered exactly for the client. For remote request objects, ProAuth applies SSRF-oriented controls documented in the PAR/JAR guide: HTTPS-only URIs, no userinfo, no fragments, exact per-client allowlists, no redirects, short fetch timeouts, response-size caps, DNS resolution before fetch, and private or loopback host blocking unless the tenant explicitly allows private-network request URIs.

Signed request objects must use asymmetric RS*, PS*, or ES* algorithms. ProAuth does not accept none or HMAC signing algorithms for signed request objects.

How this appears in ProAuth v3 preview

ProAuth discovery metadata advertises PAR and JAR support through fields such as pushed_authorization_request_endpoint, request_parameter_supported, request_uri_parameter_supported, require_request_uri_registration, and supported request-object signing and encryption algorithms. When tenant-level PAR enforcement is enabled, discovery includes require_pushed_authorization_requests.

The tenant options define the default posture:

OptionDefaultRole
PushedAuthorizationRequestLifetime00:01:30Lifetime of a pushed request URI
RequirePushedAuthorizationRequestsfalseTenant-level PAR enforcement for clients that inherit tenant policy
ParRequestFetchTimeoutInSeconds5Timeout for registered remote request-object fetches
ParRequestFetchMaxBytes102400Response-size cap for registered remote request-object fetches
AllowPrivateNetworkRequestUrisfalseWhether remote request object URIs may resolve to private networks

Client applications can then inherit or override PAR enforcement with RequirePushedAuthorizationRequests: null inherits tenant policy, true requires PAR, and false allows direct authorization requests. For JAR, RequestObjectSigningAlg can require a signing algorithm for the client, while RequestObjectEncryptionAlg and RequestObjectEncryptionEnc define optional JWE requirements.

Request-object signing keys are configured as Client App Key Sets with usage RequestObjectSigning. That is the v3 model: public keys for validating JAR request objects live in ClientAppKeySet records, not directly on the client application.

Use PAR, JAR, or both deliberately

PAR is the first answer when the problem is the browser front channel. It keeps rich authorization request data out of the redirect URL, reduces URL-length pressure, and lets ProAuth validate the request before the user is sent through the authorization interaction. For FAPI-style clients, this is not optional guidance: the FAPI 2.0 Security Profile requires clients using the authorization code flow to use PAR and to send only client_id and request_uri to the authorization endpoint.

JAR is the answer when the request parameters need cryptographic integrity. It is especially useful where request content crosses organizational boundaries, where clients need stronger evidence of what they asked for, or where a parameter change should fail instead of becoming a subtle authorization behavior change.

Using them together is often the cleanest high-assurance pattern. PAR moves the full request off the browser URL and into a direct POST. JAR signs what the request says. The result is a flow where the request is both transported through a safer channel and protected against silent parameter drift.

That does not mean every client needs the full set on day one. A practical rollout usually starts with the clients where the authorization request has the highest value: regulated workflows, sensitive APIs, cross-organization integrations, payment or delegated-action scenarios, and clients moving toward FAPI 2.0 controls.

For implementation details, start with the ProAuth PAR and JAR documentation, the Client App Key Sets documentation, and the broader ProAuth v3 release notes. For the standards background, read RFC 9126, RFC 9101, and the FAPI 2.0 Security Profile.