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

OAUTH 2.0 · LAB

Break pushed requests, then require PAR for one client

Trigger each push error from the lesson's table, show that URL parameters beside a reference are ignored, require PAR for lab-printer, and try the relaxed return-address rule for authenticated pushes.

PlannedUses your lab tenant

The lesson

Builds on: Using the request URI.

New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.

Planned. The core of this lab waits on platform features that are not built yet. The planned walkthrough shows exactly how it will run; Do today is a real exercise you can do now.

Request console

Requests in this lab can be sent from this page to your tenant: open one and choose Send. Fill in the values below first. They stay in this page's memory and are gone when you leave; secrets are never stored or sent anywhere except the request you send.

Setup

  1. Use lab-printer, lab-printer-app and the shell variables from the earlier PAR labs. Start btl-lab callback before each browser attempt.

  2. Planned (G11): in OAuth > Flow policy, keep pushed authorization requests Allowed and leave Require PAR for all clients off.

  3. Planned (G11): on lab-printer, leave Require PAR and Allow redirect URIs supplied in a push off for now.

Planned walkthrough

  1. Push with a typo in the return address, redirect_uri=http://127.0.0.1:8765/callbak.

curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$ISSUER/oauth/par" -d response_type=code -d client_id=$CLIENT_ID \
  --data-urlencode redirect_uri=http://127.0.0.1:8765/callbak --data-urlencode "scope=openid photos.read" \
  -d state=$STATE -d code_challenge=$CHALLENGE -d code_challenge_method=S256 | jq .

Expect 400 {"error":"invalid_request","error_description":"..."} as JSON.

Why it matters: "Errors from the push". In the browser this mistake ends on the tenant's error page. At the push there is no redirect to protect, so the tenant can say what went wrong.

  1. Work through the rest of the lesson's table, and write down the client's next step for each:

    • scope=openid photos.delete: 400 invalid_scope. Fix the request or the registration.

    • A state value of about 2 MB: 413. Reduce the request.

    • Pushes in a short loop until the tenant answers 429 with Retry-After: wait before trying again. The limit appears as a usage policy in the tenant's usage view.

Why it matters: each row has a different correct response, and none of them is "retry the same push" or "fall back to an ordinary authorization URL".

  1. Push a valid request, then add a parameter in the address bar beside the reference.

echo "$ISSUER/oauth/authorize?client_id=$CLIENT_ID&request_uri=$(urlenc "$REQUEST_URI")&scope=$(urlenc 'openid photos.read photos.delete')"

Open it and sign in as Ava. The consent screen shows only photos.read. If the tenant chooses strict mode, the request is refused instead.

Why it matters: "Parameters in two places". Only the stored parameters count, so an edit in the browser cannot change what the client pushed.

  1. Turn on Require PAR for lab-printer. Discovery still says require_pushed_authorization_requests: false for the tenant, while the client's record says true. Open an ordinary authorization URL for lab-printer: the listener receives error=invalid_request.

Why it matters: offering PAR without closing the ordinary route protects only the requests that choose the new route.

  1. Turn on Allow redirect URIs supplied in a push for lab-printer, with the allowed prefix http://127.0.0.1:8765/callback/. Push with redirect_uri=http://127.0.0.1:8765/callback/review-482, which is not registered. Expect 201, and after approval the callback arrives at the new path.

Why it matters: because the tenant authenticated the client first, it can safely relax exact matching inside a boundary the tenant chose.

Restore: turn Allow redirect URIs supplied in a push off on lab-printer and save.

  1. Try the same unregistered return address in a push from lab-printer-app, which has no credential. Expect 400 invalid_request. The setting is not offered for public clients.

Why it matters: the relaxation must never extend to unauthenticated pushes, or anyone could send people and their codes to an address of their choosing.

Do today

  1. Compare where today's return-address mistakes surface. Open an authorization URL for lab-printer with redirect_uri=http://127.0.0.1:8765/other: the tenant shows its own error page and the listener receives nothing.

  2. Make the same mistake at the token endpoint instead. Get a code with the correct address, then redeem it with the wrong one.

curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$ISSUER/oauth/token" -d grant_type=authorization_code \
  -d code=<code> --data-urlencode redirect_uri=http://127.0.0.1:8765/other -d code_verifier=$VERIFIER | jq .

The answer is 400 invalid_grant, and Audit shows oauth.token rejected redirect_uri_mismatch. Note how much later each mistake surfaces than it would at a push, and that the first one never reaches the client at all.

  1. Confirm the method rule from the lesson's table.

GET$ISSUER/oauth/par Open in console
GET $ISSUER/oauth/par

The answer is 405 with Allow: POST.

  1. Look for the settings the lesson describes. Discovery has no require_pushed_authorization_requests, and the lab-printer form has no Require PAR option. Note that with no PAR at all, every request for this client takes the ordinary route.

Break it

These run once G11 exists.

  1. Expired reference: push, wait past expires_in, then open the address. The tenant shows its error page with invalid_request_uri, and no callback arrives. The client's pending attempt simply times out; the fix is to push immediately before redirecting.

  2. With Require PAR on, try to set the redirect prefix to https://, which would allow every address. The tenant refuses the setting, because a prefix must include a host.

Check your work

Today, Audit shows oauth.token rejected redirect_uri_mismatch, and Logs show oauth.par rejected method_not_allowed. Once G11 exists, Audit also shows oauth.par rejections for the return address, scope and rate limit, an oauth.authorize refusal because PAR is required, and tenant.oauth.clients.update for the Require PAR and redirect prefix changes.

Cleanup

  1. Turn Require PAR off on lab-printer, so later labs can use ordinary requests.

  2. Confirm Allow redirect URIs supplied in a push is off.

Missing infrastructure

  • G11: beyond the PAR endpoint, this lab needs a per-client require_pushed_authorization_requests setting, a tenant-wide requirement, a per-client redirect prefix for authenticated pushes (never for public clients), a request size limit that answers 413, and a push rate limit registered as a visible tenant usage policy. Once these exist, the Planned walkthrough runs as written.

Back to all labs

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

The Lab