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

Register return addresses and see what consent shows

Register several exact return addresses, watch the tenant refuse unsafe ones, see that a client's name is free text on the consent page, and narrow a client's settings until wrong requests fail.

Partly readyUses your lab tenant

The lesson

Builds on: Client IDs and registration.

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

Partly ready. Most of this lab runs today. Steps that wait on platform features are marked, and Missing infrastructure says what they need.

Your progress

Press Start before you begin. Only events your tenant records after that count, in the order below. Checking reads your tenant's Audit, so you need Audit read access in it.

  1. A second registered return address is accepted

    Recorded as oauth.authorize succeeded (request_started) for lab-printer.

  2. An unsafe redirect URI registration is refused

    Recorded as tenant.oauth.clients.update rejected.

  3. Register a separate test client

    Recorded as tenant.oauth.clients.create succeeded.

  4. The test address works only for the test client

    Recorded as oauth.authorize succeeded (request_started) for lab-tmp-printer-test.

  5. A narrowed client cannot request a common scope

    Recorded as oauth.authorize rejected (invalid_scope) for lab-tmp-printer-test.

Setup

  1. Press Start on this page.

  2. Open OAuth > Clients > lab-printer > Edit, add a redirect URI http://127.0.0.1:8765/oauth/add-account/callback, and save.

  3. Set ISSUER, PRINTER_ID, APP_ID and enc, and define a request that changes only the client and return address.

eval "$(btl-lab pkce)"; eval "$(btl-lab state)"
try() { echo "$ISSUER/oauth/authorize?response_type=code&client_id=$1&redirect_uri=$(enc "$2")&scope=${3:-photos.read}&state=$STATE&code_challenge=$CHALLENGE&code_challenge_method=S256${4:+&$4}"; }

Walkthrough

  1. Use each registered address. try "$PRINTER_ID" http://127.0.0.1:8765/oauth/add-account/callback reaches the sign-in page. try "$PRINTER_ID" http://127.0.0.1:8765/oauth/other/callback stops on the tenant's error page. Close both tabs.

Why it matters: a client can register several return addresses, each request names one, and only an exact entry in the list matches.

  1. Try to save unsafe registrations on lab-printer, one at a time. Each is refused and nothing changes.

Redirect URIWhy the tenant refuses it
https://*.printer.example/oauth/callbacka wildcard would let any subdomain receive codes
http://printer.example/oauth/callbackplain HTTP is allowed only for loopback
http://localhost:8765/callbackloopback must be the literal 127.0.0.1 or [::1]
https://printer.example/oauth/callback#donea fragment
http://127.0.0.1:8765/callback?code=1the query uses a name the response adds
example.printer:/oauth/callbacka private-use scheme, not supported here (G54)
  1. Return addresses for installed apps. lab-printer-app registers http://127.0.0.1/callback with no port, and its loopback flow in earlier labs used port 8765. try "$APP_ID" http://127.0.0.1:51234/callback reaches the sign-in page too, while try "$APP_ID" http://127.0.0.1:51234/other stops on the error page.

Why it matters: for loopback addresses the port may vary, because the operating system picks a free one, and everything else still matches exactly. Plain HTTP is acceptable because the response never leaves the machine.

  1. Keep test and production apart. Create a temporary client from Web application named lab-tmp-printer-test, with redirect URI http://127.0.0.1:8765/test/callback, and set TEST_ID to its client ID. try "$PRINTER_ID" http://127.0.0.1:8765/test/callback stops on the error page. try "$TEST_ID" http://127.0.0.1:8765/test/callback reaches the sign-in page.

Why it matters: the test site's return address belongs only to the test client. Had it been added to lab-printer, a mistake on the test site could leak codes for real accounts.

  1. The name is a claim. Rename lab-tmp-printer-test to lab-printer, the same display name as the real client. Renaming revokes nothing. Open try "$PRINTER_ID" "$REDIRECT_URI" photos.read prompt=consent and try "$TEST_ID" http://127.0.0.1:8765/test/callback photos.read prompt=consent, sign in as Ava, and compare the two consent pages without approving. They look identical, although the two return addresses differ.

Why it matters: anyone who can register a client can type a familiar name. The return address is the part the server enforces, and this consent page does not show it.

  1. Narrow the test client's settings. Rename it back to lab-tmp-printer-test, tick Restrict scopes with no assigned scopes, and save. A restricted client may use only the exclusive scopes assigned to it, so try "$TEST_ID" http://127.0.0.1:8765/test/callback now returns error=invalid_scope to its callback.

Why it matters: settings that match the client's real behavior turn mistakes into ordinary rejections, and give someone holding the client's credentials less to work with.

Planned walkthrough

These steps need client display metadata on consent (G53).

  1. On lab-printer, set client_uri to https://printer.example, a logo_uri, policy_uri and tos_uri. Start a consent for Ava: the page shows the logo, the links and the return domain next to the name.

  2. Give lab-tmp-printer-test the same name and logo with a different client_uri. The consent page marks its unverified domain and shows a different return domain, so Ava can tell the two apart by domain instead of by name.

Break it

Step 2 is the set of deliberate registration failures. Nothing is saved.

Check your work

Press Check my progress. Logs also has oauth.authorize rejected invalid_redirect_uri rows for each address in steps 1, 3 and 4 that stopped on the error page.

Cleanup

  1. Delete lab-tmp-printer-test.

  2. On lab-printer, remove the http://127.0.0.1:8765/oauth/add-account/callback redirect URI and save.

Missing infrastructure

  • G53, client display metadata. Clients have only a name today: no client_uri, logo_uri, policy_uri, tos_uri or contacts, and the consent page does not show the return domain. With them, the planned steps compare a genuine and an impostor-named client by domain, and the tenant can mark clients whose domain is unverified.

  • G54, private-use URI scheme redirects. Native apps cannot register a scheme such as example.printer:/oauth/callback. With it, the lab would register one for lab-printer-app and show why PKCE still protects a code delivered to another app that claimed the same scheme.

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