Skip to main content

Pushed Authorization Requests (PAR)

Pushed Authorization Requests (RFC 9126) let a client send authorization parameters to ThunderID over a direct, authenticated back-channel before redirecting the user's browser to /oauth2/authorize. ThunderID stores the parameters and returns an opaque request_uri that the client uses in the redirect.

PAR removes sensitive parameters (scope, redirect_uri, state, claims, resource, code_challenge) from the browser URL and from any intermediate logs. It also lets ThunderID reject tampered authorization requests at the source: once a request is pushed, the only thing that can travel through the front-channel is the opaque request_uri.

How It Works

How ThunderID Implements It
AspectBehavior
EndpointPOST /oauth2/par
Client authenticationRequired, same method as /oauth2/token (see Client Authentication Methods)
Request lifetimeThe returned request_uri is single-use and expires after a short TTL
request_uri formaturn:ietf:params:oauth:request_uri:<opaque>
Per-application enforcementrequirePushedAuthorizationRequests: true on the application requires PAR for every authorization request
Global enforcementoauth.par.require_par: true in deployment.yaml requires PAR for every client
DPoP interactionWhen DPoP is in use, a DPoP proof on the PAR request binds the resulting authorization code to the proof's public key
Failure modeDirect GET /oauth2/authorize requests without a request_uri are rejected with invalid_request when PAR is required

When both the global flag and the per-application flag are set, the per-application flag adds enforcement on top: there is no way to opt out of a globally required PAR.

Try It in ThunderID

Enable per Application (Console)

  1. Open Applications or Agents in the ThunderID Console and select your client.
  2. Open the Advanced Settings tab.
  3. Toggle Require Pushed Authorization Requests on.
  4. Save.

Enable per Application (DCR)

POST /oauth2/dcr/register
Content-Type: application/json

{
"client_name": "My App",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"require_pushed_authorization_requests": true
}

Enable Globally (deployment.yaml)

oauth:
par:
require_par: true

Push and Redirect

# 1. Push the request
curl -X POST https://thunderid.example.com/oauth2/par \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "response_type=code" \
-d "client_id=$CLIENT_ID" \
-d "redirect_uri=https://app.example.com/callback" \
-d "scope=openid profile" \
-d "state=xyz" \
-d "code_challenge=$CODE_CHALLENGE" \
-d "code_challenge_method=S256"

Response:

{
"request_uri": "urn:ietf:params:oauth:request_uri:abc123...",
"expires_in": 60
}
# 2. Redirect the user
GET /oauth2/authorize
?client_id=$CLIENT_ID
&request_uri=urn:ietf:params:oauth:request_uri:abc123...

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.