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

Following a JARM exchange

The printer has decided to ask the photo service for signed authorization responses. Nothing changes for you: you select Connect, sign in, and approve, as before. What changes is one parameter in the request and the shape of what arrives at the printer's callback.

Asking for a signed response

All domains, codes, and keys in these examples are fictional. Before it relies on signed responses, the printer confirms that the photo service supports them and agrees on an algorithm:

Photo service metadata (excerpt):
{
  "issuer": "https://auth.photos.example",
  "response_modes_supported": ["query", "fragment", "form_post",
    "query.jwt", "fragment.jwt", "form_post.jwt", "jwt"],
  "authorization_signing_alg_values_supported": ["ES256"]
}

Printer registration (excerpt):
{
  "client_id": "photo-printer",
  "authorization_signed_response_alg": "ES256"
}

The registration value matters more than it looks. When a client does not specify an algorithm for signed responses, JARM's default is RS256, an RSA algorithm. A service whose signing key is an elliptic curve key, as the photo service's is, and a client that never set the value can fail to agree on a signature for reasons that have nothing to do with security.

The printer then adds one parameter to its authorization request:

https://auth.photos.example/authorize
  ?response_type=code
  &client_id=photo-printer
  &redirect_uri=https%3A%2F%2Fprinter.example%2Foauth%2Fcallback
  &scope=photos.read
  &state=demo-attempt-7
  &code_challenge=qd-75t-gnweZAhIl6REjxxgFnPXGwvqYcxq3vlsaJYQ
  &code_challenge_method=S256
  &response_mode=jwt

response_mode=jwt asks for a signed response in the default encoding for this response type. The parameter is part of the request like any other, so a printer that pushes its requests or signs them puts it in the pushed request or the request object instead of the URL.

Reading the response

After you approve, the photo service redirects your browser to the callback:

HTTP/1.1 302 Found
Location: https://printer.example/oauth/callback?response=eyJhbGciOiJFUzI1NiIsImtpZCI6InBob3Rvcy0yMDI2LTA5In0.eyJpc3MiOiJodHRwczovL2F1dGgucGhvdG9zLmV4YW1wbGUiLCJhdWQiOiJwaG90by1wcmludGVyIiwiZXhwIjoxNzkwODQ1NTAwLCJjb2RlIjoiZGVtby1jb2RlLTciLCJzdGF0ZSI6ImRlbW8tYXR0ZW1wdC03In0...

The signature is shortened here for display. There is no code, state, or iss parameter beside it. The query string holds a single parameter, response, and everything else is inside. Decoded, the JWT reads:

Header:
{
  "alg": "ES256",
  "kid": "photos-2026-09"
}

Claims:
{
  "iss": "https://auth.photos.example",
  "aud": "photo-printer",
  "exp": 1790845500,
  "code": "demo-code-7",
  "state": "demo-attempt-7"
}

The header names the algorithm and the key, one of the signing keys in the photo service's key set. In the claims, iss is the photo service's issuer identifier, the same value the plain iss parameter has carried since Redirects and authorization codes. aud is the printer's client ID. Compare that with the request object in Building a request object, whose aud named the authorization server: each signed message is addressed to the party that should accept it. exp is 2026-10-01 09:05 UTC, five minutes after the response was issued at 09:00.

Then come the ordinary response parameters, code and state, with the same values as before. A response for another response type would carry that type's parameters in the same way, and a server may add further claims, which the client ignores if it does not recognize them.

Decoding is not validating. Anyone can read these claims, and anyone could write a JWT that contains them. The printer uses none of them until the checks in Response validation and failures have passed.

Choosing a response mode

JARM defines four response modes:

Response modeWhere the JWT travels
query.jwtIn the response parameter of the callback's query string.
fragment.jwtIn the URL fragment, after #. Browsers do not send the fragment to the server, so script on the callback page has to read it.
form_post.jwtIn the body of a form that the browser posts to the callback.
jwtThe default encoding for the response type: query.jwt for the code flow, and fragment.jwt for response types that return tokens from the authorization endpoint.

The printer's jwt therefore meant query.jwt. The query string is acceptable for a response that carries a code, which is single-use and protected by PKCE. It is not acceptable for responses that carry tokens: the specification forbids query.jwt for response types that return access tokens or ID tokens from the authorization endpoint, unless the JWT is encrypted.

With form_post.jwt, the photo service answers your browser with a small page that submits itself:

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Cache-Control: no-cache, no-store

<html>
  <body onload="document.forms[0].submit()">
    <form method="post" action="https://printer.example/oauth/callback">
      <input type="hidden" name="response" value="eyJhbGciOiJFUzI1NiIsImtpZCI6InBob3Rvcy0yMDI2LTA5In0...">
    </form>
  </body>
</html>

The JWT then reaches the printer in a POST body, so it stays out of the address bar, browser history, and the Referer header. One side effect catches teams out when they switch. As Request correlation and CSRF noted, a form posted from another site does not carry SameSite=Lax cookies, so the cookie that identifies your pending attempt must be set up for that case, or the printer will find it missing at its callback.

Whichever mode carries it, the JWT is the same, and so are the checks the printer applies before it touches the code.

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 2The printer sends response_mode=jwt with response_type=code. How does the response arrive?

QUESTION 2 OF 2The printer's developer assumes a JARM response is addressed like the request objects the printer sends. Which aud value does a genuine JARM response to the printer actually carry?

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