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

Writing authorization details

The printer's developer now has two requests to write: read album 42 at the photo service, and pay 42.50 EUR at Lakeside Bank. Both go into the authorization_details parameter, but neither service accepts whatever JSON a client sends. Each type comes with a definition, published by the service, that says which fields an object may contain and what they mean.

The type and its definition

Every object in the array must have a type, the only field Rich Authorization Requests requires everywhere. The type identifies a kind of access at a particular API. The authorization server controls what each type means and which other fields an object of that type may contain. An array can hold several objects, including several of the same type.

Developers copy type values from documentation, so they should be easy to copy exactly. Plain ASCII avoids characters that look identical but are different. A type used by one service can be a short name such as photo_album. A type meant to be used at many different servers, such as one written into an industry standard, should be a URI controlled by whoever defines it, so that two unrelated definitions cannot choose the same name.

Common fields

The specification also defines five common fields that a type can reuse. None of them is required. A type definition decides which ones it uses and which values each one may hold.

FieldMeaningIn the album request
locationsWhere the access will be used, usually the URI of an API.The photo API.
actionsWhat the client wants to do.Read.
datatypesWhich kinds of data it wants.Images and captions, but not where each photo was taken.
identifierOne specific resource at the API.Album 42.
privilegesA type or level of privilege, such as a role.Not used by this type.

All domains, identifiers, accounts, and values in these examples are fictional. Put together, the printer's request for the photo book reads:

[
  {
    "type": "photo_album",
    "locations": ["https://api.photos.example"],
    "actions": ["read"],
    "datatypes": ["images", "captions"],
    "identifier": "42"
  }
]

When an object lists several values, it asks for every combination of them: each action, at each location, for each datatype. This object asks to read images and to read captions. To ask for one combination without the others, a client sends separate objects. If you chose two albums for the book, the printer would send two photo_album objects, one with the identifier 42 and one with 57, because identifier holds a single value.

Fields that belong to one type

Most of what a payment needs has no common field. A type definition can add fields of its own, and Lakeside Bank's payment type adds the amount, the recipient, and a reference:

[
  {
    "type": "payment_initiation",
    "locations": ["https://api.lakeside-bank.example/payments"],
    "actions": ["initiate", "status"],
    "instructedAmount": { "currency": "EUR", "amount": "42.50" },
    "creditorName": "Photo Printer",
    "creditorAccount": { "accountId": "demo-merchant-account-17" },
    "remittanceInformationUnstructured": "Photo book order book-5561"
  }
]

The field names come from the bank's definition, which borrows the vocabulary of banking payment standards. The creditor is the party receiving the money, and the remittance information is the reference that appears on both sides' statements. The two actions let the printer start the payment and later check its status. Lakeside Bank's definition also says that one approval covers one payment, so nothing in the object needs to say "once".

The amount is a string. Values in authorization details are compared exactly as written, without normalizing them, so "42.50" and "42.5" are different values. The bank's definition says which form to use, and the client writes the amount that way. Notice also that creditorName is text the printer chose. The account identifier says where the money goes, and the name is only how the printer describes itself.

Sending the details

Authorization details can appear wherever a scope would carry the same kind of request, including the authorization request and the device authorization request. In an authorization request, the array is serialized as JSON and URL-encoded as one more parameter. The album request becomes:

https://auth.photos.example/authorize
  ?response_type=code
  &client_id=photo-printer
  &redirect_uri=https%3A%2F%2Fprinter.example%2Foauth%2Fcallback
  &authorization_details=%5B%7B%22type%22%3A%22photo_album%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fapi.photos.example%22%5D%2C%22actions%22%3A%5B%22read%22%5D%2C%22datatypes%22%3A%5B%22images%22%2C%22captions%22%5D%2C%22identifier%22%3A%2242%22%7D%5D
  &state=demo-attempt-12
  &code_challenge=ySTBkLMnXWUiL2an2t3T9j9a9GgE6O651oR_30KaWF0
  &code_challenge_method=S256

There is no scope parameter this time. The details describe all the access the printer wants.

The album request is long, but nothing in it is sensitive. The payment request is close to 500 characters once encoded, and it would carry an amount, an account, and an order reference through the browser's address bar, its history, and any logs or Referer headers that record the address. Anything in that address can also be changed before it reaches the bank, by the person using the browser or by malicious software running there. When the integrity of the details matters, and for a payment it does, the specification requires the client to protect them, either by signing the request as JWT-Secured Authorization Requests describes or by sending it directly to the server.

Pushed Authorization Requests suits this well. The printer sends the whole request, details included, to the bank's PAR endpoint over a direct connection, and authenticates as it would at the bank's token endpoint. Lakeside Bank accepts only key-based client authentication, so the photo-printer-pay registration uses private_key_jwt with the printer's key printer-2026-10, the method the Secrets and signed assertions lesson described:

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

response_type=code
&client_id=photo-printer-pay
&redirect_uri=https%3A%2F%2Fprinter.example%2Fpay%2Fcallback
&authorization_details=%5B%7B%22type%22%3A%22payment_initiation%22%2C...
&state=demo-attempt-14
&code_challenge=0AO-1LrNoVHelP9ShWySwBTeUtdaRAk371ho0dMw3MI
&code_challenge_method=S256
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6InByaW50ZXItMjAyNi0xMCIsInR5cCI6IkpXVCJ9...

The details and the client assertion are shortened here for display. As the Pushed Authorization Requests lessons showed, the bank answers with a request URI, and your browser carries only the client ID and that reference to the authorization endpoint. The amount and the account never appear in an address bar, and the bank can check the whole request before you see a consent screen.

Writing the details is the client's half of the work. The authorization server still has to decide whether the request makes sense, ask you about it, and pass what you approved to the API.

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 2A photo_album object lists the actions read and delete, and the datatypes images and captions. What does it ask for?

QUESTION 2 OF 2Why does the printer send its payment details to Lakeside Bank with a pushed authorization request instead of in the browser URL?

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