Skip to main content

PAR response (RFC 9126)

The Pushed Authorization Request is the only authorisation channel into the OID4Pay AS. See also the four-signature trail and the agent quickstart.

The shape

POST /oauth/par returns ONLY {request_uri, expires_in} per RFC 9126 §2.2. Consent resolution does not happen here; it happens inside /oauth/authorize. Do not expect a status field on this response.

Wire shape

POST https://as.oid4pay.com/oauth/par
Content-Type: application/x-www-form-urlencoded
DPoP: <DPoP proof JWT>

client_id=<agent_client_id>
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<private_key_jwt>
&response_type=code
&scope=oid4ac:payment
&code_challenge=<PKCE S256>
&code_challenge_method=S256
&redirect_uri=<agent callback>
&resource=https://shop.alpacanica.com
&authorization_details=[{
  "type": "oid4ac_mandate",
  "amount_minor": 1299,
  "currency": "EUR",
  "merchant": "https://shop.alpacanica.com",
  "line_items": [...],
  "offer_digest": "<b64url SHA-256 of canonical Offer>"
}]

201 response

HTTP/1.1 201 Created
Content-Type: application/json
Cache-Control: no-store

{
  "request_uri": "urn:ietf:params:oauth:request_uri:abc...",
  "expires_in": 60
}

Flow

POST as.oid4pay.com/oauth/par           -> 201 {request_uri, expires_in}       (RFC 9126 §2.2)
GET  as.oid4pay.com/oauth/authorize     -> {auto: 302 with code+iss; dashboard/scan: 302 to consent_url, then back-channel poll}
POST as.oid4pay.com/oauth/token         -> 200 {access_token, token_type:"DPoP", expires_in, refresh_token, mandate_jwt}

Worked example

$ curl -sS https://as.oid4pay.com/oauth/par \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "DPoP: $DPOP_PROOF" \
    --data-urlencode "client_id=$CLIENT_ID" \
    --data-urlencode "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
    --data-urlencode "client_assertion=$PKJ_JWT" \
    --data-urlencode "response_type=code" \
    --data-urlencode "scope=oid4ac:payment" \
    --data-urlencode "code_challenge=$CHALLENGE" \
    --data-urlencode "code_challenge_method=S256" \
    --data-urlencode "redirect_uri=https://my-agent.example.com/callback" \
    --data-urlencode "resource=https://shop.alpacanica.com" \
    --data-urlencode "authorization_details=$AUTHZ_DETAILS"

201 Created
{"request_uri":"urn:ietf:params:oauth:request_uri:a8c2...","expires_in":60}

Errors

CodeReason
invalid_dpop_proofDPoP proof missing, expired, or replayed.
use_dpop_nonceAS requires a fresh nonce; retry with the nonce in the DPoP proof's nonce claim.
invalid_clientprivate_key_jwt assertion failed.
invalid_authorization_detailstype=oid4ac_mandate body missing a required field (amount_minor, currency, merchant, offer_digest).