Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

Using JAR with PAR

PAR and JAR attack the same weakness from different directions. PAR changes the route, so the request never passes through the browser. JAR changes the request, so it carries a signature wherever it goes. Neither depends on the other, and they fit together naturally: the printer can sign its request object and push it.

Pushing a signed request

The push in Pushing an authorization request carried a Basic header with the printer's client secret. Since then, the printer's registration has switched to private_key_jwt, as Building a request object described: a client that already manages a key pair to sign its requests gains little from keeping a shared secret as well, and high-assurance deployments authenticate with keys. So this push authenticates with a signed client assertion.

All domains, keys, and identifiers in these examples are fictional. The printer signs the request object from Building a request object and sends it to the PAR endpoint:

POST /par HTTP/1.1
Host: auth.photos.example
Content-Type: application/x-www-form-urlencoded

client_id=photo-printer
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6InByaW50ZXItMjAyNi0xMCIsInR5cCI6IkpXVCJ9...
&request=eyJhbGciOiJFUzI1NiIsImtpZCI6InByaW50ZXItMjAyNi0xMCIsInR5cCI6Im9hdXRoLWF1dGh6LXJlcStqd3QifQ...

Both JWTs are shortened here for display. The body looks sparse compared with the push in Pushing an authorization request, and that is the rule: apart from request, the form body carries only what client authentication needs. Every parameter of the authorization request itself, the scope, return address, state, and PKCE challenge, must appear as a claim inside the signed object, not as a form field beside it.

The response is the same 201 Created with a request_uri and expires_in, and your browser then visits the authorization endpoint with nothing but client_id and that reference, exactly as in Using the request URI.

What the server checks

The photo service combines the checks from both groups. It authenticates the client as it would at the token endpoint and refuses a push containing request_uri. It then decrypts the object if it is encrypted and verifies its signature with a key registered for the printer.

One check is new. Because the printer has credentials and has just authenticated, the service rejects the push if the authenticated client is not the client named by the client_id claim inside the object. Whether the object's iss must also equal the client ID is left to the service. Finally, it validates the request as an authorization request, stores it, and issues the reference.

The push carries two JWTs signed with the same key, printer-2026-10, and the service must never confuse them:

Client assertionRequest object
PurposeAuthenticates the printer for this push.Carries the authorization request.
typJWT, as in Secrets and signed assertions. Newer guidance recommends client-authentication+jwt.oauth-authz-req+jwt
iss and subBoth photo-printer.iss is photo-printer. No sub naming the client.
audThe photo service's issuer identifier.The photo service's issuer identifier.
LifetimeAbout a minute.Five minutes in this example.

Both name the printer as issuer and the photo service as audience. What keeps each from passing for the other is the typ and sub rows, as Building a request object explained.

What each part contributes

Combining the two gives each one's strengths and removes most of their weaknesses:

PAR aloneJAR without PARJAR with PAR
Parameters hidden from the browserYesBy value only if encrypted; yes by referenceYes
Parameters protected from changesYes, by the routeYes, by the signatureYes, by both
Client known before you are involvedYes, by client authenticationYes, by the signatureYes, by both
Short browser URLYesNo by value; yes by referenceYes
Server fetches from a client-hosted addressNeverOnly by referenceNever
Signed evidence of the request afterwardsNoYesYes

Two rows explain why the combination is popular. PAR removes the need for the server to fetch objects from addresses that came through a browser, along with all the precautions that fetch required, because the server issues the reference itself and already holds what it points to. And JAR adds the one thing PAR cannot provide: a signature over the exact request, which the server can keep and show to someone else.

For connecting a photo account, PAR alone is often enough. The signed evidence earns its cost where someone may later need to prove what was asked for.

Why high-assurance profiles combine them

Payments are the clearest case. When the printer asks Lakeside Bank to approve your 42.50 EUR photo book payment, the bank wants the request to arrive unaltered, from an authenticated client, before you see an approval screen, and it wants to keep a record the printer cannot later disown. Neither mechanism delivers all of that alone.

Industry security profiles for banking and similar sectors, written by the OpenID Foundation as the Financial-grade API (FAPI) profiles, show how that thinking developed. The earlier FAPI 1.0 Advanced profile required signed request objects. The FAPI 2.0 Security Profile, final since 2025, made client-authenticated PAR mandatory for every authorization request instead and does not require JAR, because a pushed request never passes through the browser where it could be read or changed. A companion profile, FAPI 2.0 Message Signing, adds signed request objects at the PAR endpoint for ecosystems that need non-repudiation. Its servers require aud to name the server's issuer identifier, an nbf no more than 60 minutes in the past, and an exp no more than 60 minutes after nbf, and its clients are asked to send the explicit typ you saw in the printer's object.

The request is now protected from the moment the printer signs it until the photo service or the bank decides on it. The FAPI security profiles group at the end of Advanced OAuth looks at these profiles as a whole, and the next group, JARM, applies the same signing idea to the authorization response on its way back.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2When the printer pushes a signed request object, where do scope, state, and the PKCE challenge go?

QUESTION 2 OF 2Why do some high-assurance deployments add JAR when they already require PAR?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity