OAUTH 2.0 · LAB
Operate your tenant as an authorization server for a day
Review the client registry and suspend a client, watch stored approvals drive consent, plan a key rotation, read the audit trail for secrets, and end access through account events.
Partly readyUses your lab tenant
The lesson
Builds on: Token formats and validation, Client credentials.
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.
- G40 Grant and consent inventory: list and revoke a user's app grants ("connected applications"), app approval policy, tenant-wide app block
- G52 Governance and usage reporting: ownership metadata, filterable last sign-in, per-client last use and usage inventory, report-only enforcement
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.
Sign in to start this lab and check your progress. Log in or create an account.
Suspend lab-print-orders
Recorded as
tenant.oauth.clients.updatesucceeded.See the suspended client refused
Recorded as
oauth.tokenrejected (client_disabled) forlab-print-orders.Publish the next signing key ahead of use
Recorded as
tenant.oauth.keys.generatesucceeded.Move signing to the new key
Recorded as
tenant.oauth.managers.updatesucceeded.End Ava's grants with a password change
Recorded as
tenant.users.credentials.setsucceeded.See the printer's refresh refused afterwards
Recorded as
oauth.tokenrejected (refresh_revoked) forlab-printer.
Setup
Choose Lab Photos as the lab tenant and press Start.
Load
CLIENT_IDandCLIENT_SECRETforlab-printer,ORDERS_IDandORDERS_SECRETforlab-print-orders, and the helpers from Rotate a refresh token family.Start a review table with one row per client in Clients: type, redirect URIs, assigned scopes, consent setting, access token manager, and when you last used it.
Walkthrough
Review the registry. For each client, check that every redirect URI is on a host you control or loopback, that its scopes match its job, and that its name on the consent screen is accurate. Fill in "last used" from Audit, filtered by client.
Note: the tenant does not record a last token issuance time per client (G52), so "last used" comes from memory or from Audit's 30-day window. A client unused for a year cannot be found this way.
Suspend a client and see it take effect at once. In Clients, set
lab-print-ordersto disabled and save. Then:
curl -s -u "$ORDERS_ID:$ORDERS_SECRET" "$ISSUER/oauth/token" -d grant_type=client_credentials -d scope=prints.create | jq .
Returns 401 invalid_client, Audit reason client_disabled.
Why it matters: the registry is how the provider suspends a misbehaving client within minutes rather than days.
Restore: set lab-print-orders back to enabled and save.
Watch the stored approval drive consent. Confirm
lab-printer's Consent interaction asks once per set of scopes. Then, withbtl-lab callbackrunning:authorize "photos.read", sign in as Ava: the consent screen asks once. Approve.authorize "photos.read"again: no consent screen, because the decision was already made.authorize "photos.read photos.share": the consent screen appears again, for the new scope.Add
&prompt=consentto aphotos.readrequest: the screen appears even though the approval is remembered.
Why it matters: the stored approval decides when the server may skip the screen, and a new scope needs a new decision rather than being covered by an old one.
Write down your lifetime decisions with a one-line reason each: the authorization code lifetime (Flow policy), session lifetime, and for each access token manager the access token lifetime, refresh idle lifetime, sign-in limit and reuse grace.
Why it matters: these are policy choices a provider makes per client and scope, and reviews when a client's needs change.
Run a planned key rotation.
In Key Management, Generate key (ES256) and leave it unused. Fetch
$ISSUER/oauth/jwks: it is published beside the current key.Edit Default access tokens and choose the new key as its signing key. New tokens carry the new
kid.Try to retire the new key, which a manager now uses: the change is refused.
Move the old key to Retiring. Disable it only after its longest-lived token has expired, an hour with the default lifetime.
Why it matters: the new key appears before it signs anything, and the old one stays published while tokens it signed are still alive, so verifiers the provider does not control keep up.
Read the audit trail as an investigator would. In Audit, look through the last day. Every entry has a time, operation, client, subject where there is one, outcome and reason. None contains a code, token, secret or password.
End access through an account event. Get a refresh token for Ava (
authorize "photos.read offline_access",exchange). In User Management, set a new password for Ava. Thenrefresh "$REFRESH":invalid_grant, Audit reasonrefresh_revoked.
Why it matters: events that should end grants must actually reach the grant records. The printer learns at its next refresh and asks Ava to reconnect.
Note: Ava has no connected applications page where she could see and remove the printer's grant herself (G40), so this lab ends the grant through a password change.
Break it
Present a wrong secret for lab-printer five times:
for i in 1 2 3 4 5; do curl -s -o /dev/null -w '%{http_code} ' -u "$CLIENT_ID:wrong-secret-wrong-secret-wrong-secret-0$i" "$ISSUER/oauth/token" -d grant_type=client_credentials; done; echo
Each is 401, and each appears in Audit as oauth.token rejected with invalid_client against the claimed client, so a known client ID being paired with guessed secrets is visible. If a protocol limit is reached, the response becomes 429 with Retry-After.
Check your work
Press Check my progress. The checks look for, in order: the suspension of lab-print-orders, its refused token request with client_disabled, the new signing key, the manager switching to it, the password change for Ava, and the printer's refused refresh.
Cleanup
Confirm
lab-print-ordersis enabled.Keep the new key active on Default access tokens. After an hour, disable the old key in Key Management.
Store Ava's new password. Run
unset REFRESH TOKEN RESP ORDERS_SECRET.
Missing infrastructure
G40 Connected applications. A per-user and per-client grant view showing what was approved, when, and when it was last used, with removal that ends the grant and every family under it. Step 7 would then remove the printer's grant from Ava's account page instead of changing her password.
G52 Client last-used report. A last token issuance time per client, so step 1 can find clients unused for a year and disable them with a message to their contacts, instead of relying on memory or the 30-day Audit window.