skip to content

How does an RFC 9126 pushed authorization request change what the browser carries to the authorization endpoint?

level: middleimportance: should knowfreq 42%

answer

  1. back channel first, browser second
  2. parameters never ride the query string
  3. server mints a short-lived reference
  4. 201 carries request_uri and expires_in
  5. redirect shrinks to client_id plus request_uri

basics

~20 s

Pushed authorization requests move the parameters off the browser. The client POSTs them to the authorization server's pushed authorization request endpoint, receives a short-lived request_uri reference, and the browser redirect then carries only client_id and that reference.

solid answer

~50 s

A pushed authorization request moves the parameter set off the front channel. Instead of putting `response_type`, `scope`, `state`, `code_challenge` and the rest into a query string, the client POSTs them form-encoded — with client authentication if it holds credentials — to the authorization server's `pushed_authorization_request_endpoint`. The server validates and stores them and answers `201` with a JSON body carrying a `request_uri` and an `expires_in`; one registered shape for the reference is the `urn:ietf:params:oauth:request_uri:` form. The browser redirect then carries only `client_id` and `request_uri`, and the server recovers the stored parameters from the reference. The gain is that the request the server acts on arrived directly from an authenticated client over the back channel and is not bounded by URL length. Support is discoverable: a server that offers the endpoint should advertise it in its RFC 8414 metadata.

code

http · 14 lines
http
POST /as/par HTTP/1.1
Host: as.example.net
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0Mzpoc2VjcmV0

response_type=code&client_id=s6BhdRkqt3&redirect_uri=https%3A%2F%2Fdisplay.example.org%2Fcb&scope=meter.read&state=af0ifjsldkj&code_challenge=K2-ltc83acc4h0c9w6ESC_rEMTJ3bww-uCHaoeK1t8U&code_challenge_method=S256

HTTP/1.1 201 Created
Content-Type: application/json

{
  "request_uri": "urn:ietf:params:oauth:request_uri:6esc_11ACC5bwc014ltc14eY22c",
  "expires_in": 60
}

go deeper

for a junior

Recall the shape: the application talks to the authorization server directly first, gets back a short ticket-like reference, and only then sends the browser off with that reference instead of a long link.

for a middle

Be able to walk the four steps and name what is in each message: form-encoded parameters plus client authentication going up, a 201 with request_uri and expires_in coming back, client_id and request_uri on the redirect.

for a senior

Show that you know what the back channel buys — validation before the user sees anything, no URL ceiling, and an authenticated origin for the parameters — and say plainly what it does not cover on the response leg.

for a principal

The judgment is whether to require it estate-wide. Weigh the metadata switch that enforces it, the extra round trip per authorization, and the clients that cannot be changed against the auditability of every request arriving authenticated.

## What a plain authorization request looks like In the OAuth 2.0 authorization code flow, the client begins by sending the resource owner's browser to the authorization server's **authorization endpoint** with every request parameter in the query string: `response_type`, `client_id`, `redirect_uri`, `scope`, `state`, `code_challenge`, `code_challenge_method`. This is the **front channel** — the leg that travels through the user agent. It works, and it carries two structural costs: - **Anything that can see or touch the URL can read and rewrite it.** The authorization server receives whatever arrives; it has no way to tell what the client originally composed. - **The request is bounded by URL length**, in practice by whatever the browsers, proxies, gateways and log pipelines in the path tolerate. A request that has grown a structured rights object, or a signed assertion, runs into that ceiling long before it runs into anything the specification says. ## The pushed exchange RFC 9126 adds one endpoint and one round trip that happens **before** the browser is involved. 1. The client POSTs the same parameters it would have put in the query string, form-encoded, to the authorization server's `pushed_authorization_request_endpoint`. A confidential client authenticates here exactly as it does at the token endpoint — for example with `client_secret_basic` or `private_key_jwt`. 2. The authorization server validates them as if it had received them at the authorization endpoint, stores them against that client, and answers **HTTP `201`** with a JSON object carrying a `request_uri` and an `expires_in`. 3. The client redirects the browser to the authorization endpoint carrying only `client_id` and `request_uri`. 4. The authorization server resolves the reference, recovers the parameters it stored, and runs the ordinary flow from them — authenticate the resource owner, obtain consent, redirect back with a code. One registered shape for the reference is the `urn:ietf:params:oauth:request_uri:` URN form followed by a high-entropy value. The `expires_in` the specification expects is short — its own example range of 5 to 600 seconds is an example rather than a requirement — because the reference exists only to bridge one client-to-browser handoff. ## What the authorization server gains | Concern | Parameters in the query string | Parameters pushed first | |---|---|---| | Where the parameters travel | Front channel, through the user agent | Back channel, client to server directly | | Who vouched for them | Whoever composed the URL | The client that authenticated at the POST | | Size ceiling | Whatever the URL chain tolerates | An ordinary request body | | Effect of editing the browser URL | Changes the request the server acts on | Changes only the reference, which then resolves to nothing | | When the request is validated | At the moment the browser arrives | Before the browser is involved at all | The last row matters more than it looks. A malformed or unauthorised request is rejected on the back channel with a plain HTTP error the client can log and act on, instead of becoming a redirect the resource owner sees. ## Discovery, and making it compulsory A server that supports the mechanism **should** advertise `pushed_authorization_request_endpoint` in its RFC 8414 authorization server metadata — a recommendation, not a requirement, so a client cannot conclude from a metadata document alone that the feature is absent. Two switches turn the option into a rule. As client metadata, `require_pushed_authorization_requests` marks one client as required to push; as authorization server metadata, the same name declares that the server requires it of every client. Once either is set, an authorization request that arrives with its parameters in the query string is rejected. ## What it does not do - **It does not authenticate the resource owner.** Nothing about the push involves the user; consent still happens after the redirect. - **It does not sign anything.** The server trusts the pushed parameters because they arrived over an authenticated back-channel connection, not because the request itself carries a verifiable signature. That is a different specification. - **It does not remove the redirect.** The browser still visits the authorization endpoint and still comes back to the client's redirection endpoint. - **It does not give the request structure.** Expressing a right with parameters — an instrument, a limit, a date range — is a separate mechanism; pushing only changes how the request is delivered. - **It is not a fetch.** The reference is minted and held by the authorization server; the server is not retrieving a document from the client.

  • What makes a pushed request trustworthy to the authorization server before any resource owner is involved?
    A confidential client authenticates at the pushed endpoint the same way it does at the token endpoint, so the server knows which client registered those parameters and can bind the reference to it. A public client with no credential may still push; the server then treats the request with exactly the trust it would give an unauthenticated one, and the benefit is reduced to keeping the parameters out of the URL.
  • How does a deployment make pushing compulsory rather than optional?
    Through `require_pushed_authorization_requests`. Set as client metadata it binds one client; published as authorization server metadata it binds every client of that server. After that, an authorization request whose parameters arrive in the query string is rejected, which is how an operator retires the front-channel form without asking each integrator to promise.
  • Does pushing the request remove the need for a proof key on a public client?
    No. Pushing protects the request on its way to the authorization server; it says nothing about the authorization response. The code still comes back through the browser to the client's redirection endpoint, so the binding between that code and the party that started the flow is a separate mechanism and still required.

saying these in an interview costs you the question

  • Thinks pushing the request replaces the browser redirect to the authorization endpoint
  • Says the request_uri is a client-hosted URL the server fetches
  • Believes the push authenticates the resource owner rather than the client
  • Expects one request_uri to stay usable for a whole session
  • Assumes every authorization server must expose a pushed-request endpoint
  • Treats pushing as protection for the authorization response as well