OAUTH 2.0 · LAB
Decide who may exchange which token, and what storage checks afterwards
Walk the authorization server's exchange checks with requests that fail at each one, confirm the capped lifetime and kept auth_time, and build storage's decision. Today, run the trust checks your tenant already makes.
PlannedUses your lab tenant
The lesson
Builds on: Scopes, resources, and audiences.
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.
- G6 Token exchange (RFC 8693)
- G55 Tenant resource (API) registry
Setup
These steps are real today.
You need
lab-printer,lab-print-ordersandlab-photo-api(with Resource server on) and their credentials in the shell asCLIENT_ID/CLIENT_SECRET,ORDERS_ID/ORDERS_SECRETandAPI_ID/API_SECRET.Confirm
lab-printerdoes not allow theclient_credentialsgrant andlab-print-ordersdoes not have Resource server on.Get a fresh printer token
ATfor Ava with alab-printercode flow forphotos.read, as in the earlier token exchange labs.
Planned walkthrough
This walkthrough runs once your tenant supports token exchange (G6) with the planned resources and exchange policies (G55).
Planned setup
On
lab-tmp-photo-storage(create it if needed), set the exchange policy: accept access tokens whoseaudishttps://storage.lab.example; targethttps://archive.lab.example; mapstorage.readtoarchive.read; delegation; 60 seconds.lab-printerkeeps no exchange grant.In OAuth > Access token managers, create
lab-tmp-at-short(JWT, lifetime 90 seconds, with theauth_timemapping) and assign it tolab-printer.
Steps
Who may exchange.
lab-printersends the exchange with its own valid token:
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$ISSUER/oauth/token" \
--data-urlencode grant_type=urn:ietf:params:oauth:grant-type:token-exchange --data-urlencode "subject_token=$AT" \
--data-urlencode subject_token_type=urn:ietf:params:oauth:token-type:access_token \
--data-urlencode resource=https://storage.lab.example -d scope=storage.read | jq .
The result is unauthorized_client.
Why it matters: without client authentication and a per-client permission, anyone holding a stolen token could use the token service to turn it into tokens for other services.
The subject token belongs with its presenter. As
lab-tmp-photo-storage, present Ava's printer token, whose audience is the photo API. The result isinvalid_request, and Audit recordsinvalid_subject_token(planned reason).
Why it matters: a client may exchange only tokens issued for the API it is registered as, so a token sent to the wrong service by mistake cannot be turned into new access.
An expired or revoked subject. Revoke
ATaslab-printer, then exchange it aslab-photo-api. The result isinvalid_request.The lifetime cap. Sign in again so
ATcomes fromlab-tmp-at-short, wait 60 seconds, and exchange it aslab-photo-api.expires_inis about 30, never past the subject token'sexp.Authentication details are kept, not refreshed. The exchanged token's
auth_timeequals the subject token's.
Why it matters: an exchange must not let authority outlive the token behind it, nor make a sign-in look more recent or stronger than it was.
Storage's decision. Start storage with
btl-lab resource --port 8767 --mode introspect --audience https://storage.lab.example --read-scope storage.read --actor <lab-photo-api ID>(planned options). A delegation token fromlab-photo-apiis allowed. A token about Ava with any other current actor, or the photo API's own client credentials token with noact, is refused even with the right scope.
Why it matters: a recipient decides on the top-level claims and the current actor only, takes the subject from the validated token, never from a path or header, and still checks that the object is the subject's.
Do today
Who may use a grant is decided per client today:
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$ISSUER/oauth/token" -d grant_type=client_credentials | jq .
The result is unauthorized_client, and Audit records oauth.token rejected unauthorized_client for lab-printer.
Who may read another client's token is decided per client too. Introspect Ava's printer token as the print orders job, then as the photo API:
curl -s -u "$ORDERS_ID:$ORDERS_SECRET" "$ISSUER/oauth/introspect" --data-urlencode "token=$AT" | jq '{active}'
btl-lab introspect "$AT"
The first prints {"active": false} (Audit token_not_found), the second active: true (Audit other_client_token_found). The Resource server flag is your tenant's trust decision about reading another client's token, the same kind of decision an exchange policy makes about presenting one.
A token belongs to its client. As the print orders job, try to revoke Ava's printer token:
curl -s -u "$ORDERS_ID:$ORDERS_SECRET" "$ISSUER/oauth/revoke" --data-urlencode "token=$AT" | jq .
The result is unauthorized_client, and Audit records oauth.revoke rejected other_client_token.
Revoked means unusable. Revoke
ATaslab-printer, then introspect it as the photo API:
curl -s -o /dev/null -w '%{http_code}\n' -u "$CLIENT_ID:$CLIENT_SECRET" "$ISSUER/oauth/revoke" --data-urlencode "token=$AT"
btl-lab introspect "$AT"
200, then active: false. An exchange of this token would be refused in the same way as step 3 of the planned walkthrough.
Check your work
There are no automated checks while this lab is planned. For Do today, look in Lab Photos' Audit for oauth.token rejected unauthorized_client for lab-printer, oauth.introspect with token_not_found for lab-print-orders and other_client_token_found for lab-photo-api, oauth.revoke rejected other_client_token for lab-print-orders, and oauth.revoke succeeded access_token_found for lab-printer.
Cleanup
If you created lab-tmp-at-short, assign lab-printer back to the manager it used before and delete it. Run unset AT.
Missing infrastructure
G6 Token exchange, with the checks in the lesson's order driven by each client's exchange policy (permitted clients, accepted subject token audiences, targets, scope mapping, lifetime cap, kept
auth_timeandacr) and a tenant-visible record linking the subject token'sjtito the issued one. The--read-scopeand--actoroptions are planned additions tobtl-lab resource.G55 Tenant resource (API) registry for the storage and archive targets.