OAUTH 2.0 · LAB
Request, approve, deny and narrow access with scopes
See registration refuse a scope before consent is shown, deny and approve consent as Ava, and watch a tenant policy issue less than she approved.
ReadyUses your lab tenant
The lesson
Builds on: Trust boundaries.
New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.
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.
Create a token policy that narrows scopes
Recorded as
tenant.oauth.managers.createsucceeded.A scope outside the registration is refused
Recorded as
oauth.authorizerejected (invalid_scope).Ava signs in and denies the request
Recorded as
oauth.authorizerejected (access_denied) about[email protected].Ava approves the request
Recorded as
oauth.authorizesucceeded (code_issued) about[email protected].The tenant policy refuses a token Ben approved
Recorded as
oauth.tokenrejected (policy_denied) about[email protected].
Setup
Press Start on this page.
Open Users > Ben Okafor > Set password and give him a test password for these labs.
Check OAuth > Scopes:
photos.readis common, whilephotos.writeandphotos.deleteare exclusive. The lesson'salbums.createplays the same part asphotos.writehere: access the printer has no need for.Open OAuth > Clients > Token Decoder > Edit. Set Consent to Ask on every request and assign the exclusive scope
photos.write. Do not assignphotos.delete. Save.In Access Token Management, create a temporary manager named
lab-tmp-scope-policy: format Signed JWT, an active signing key. Under Advanced issuance policy enter the script below, use Test with sample context to see its result, and save. Do not assign it yet.
return {allow: true, claims: {}, scopes: context.scopes.filter(scope => scope !== 'photos.write')};
Walkthrough
Open
$ISSUER/token-decoder, set Scopes tophotos.read, sign in as Ava and approve. The decoder then exchanged the authorization code at the token endpoint withgrant_type=authorization_code.
Why it matters: the authorization code is the authorization grant, the credential the client presents. authorization_code is the grant type, the method used at the token endpoint to present it.
Set Scopes to
photos.read photos.deleteand start again. The decoder reportserror=invalid_scopeat once: no sign-in page and no consent page.
Why it matters: the client's registration limits what it can request at all. Consent is never offered for access the registration excludes.
Set Scopes to
photos.read photos.write. The consent page lists both. Choose Deny. The decoder reportserror=access_denied.
Why it matters: Ava signed in successfully and still refused. Signing in establishes control of the account; approving the connection is a separate decision.
Repeat step 3 and choose Approve. The token response says
scope: "photos.read photos.write".
Open OAuth > Clients > Token Decoder, set Access token manager to
lab-tmp-scope-policyand save. Repeat step 4: Ava approves both scopes, and the token response now saysscope: "photos.read".
Why it matters: approval cannot override the service's policy. The client must read the scope it actually received instead of assuming every requested capability was granted.
In the Token Decoder's settings, set Consent to Ask once per set of scopes and save. Request
photos.readtwice in a row as Ava: the second time there is no consent page. Requestphotos.read photos.write: consent appears again for the larger set.
Why it matters: a remembered approval is the saved-connection kind of "grant" a product records. It is a different thing from the code presented in each token request.
Break it
Change the
lab-tmp-scope-policyscript so the tenant refuses Ben, and save.
return {allow: context.subject.email !== '[email protected]', claims: {}};
In the Token Decoder, tick Ask me to sign in again, request
photos.read, sign in as Ben and approve. The token endpoint answersinvalid_grantwith "The tenant's access token policy refused to issue this token."
Ben approved, and the tenant still said no. Consent is one input to the decision, not the whole decision.
Restore: in OAuth > Clients > Token Decoder, set Access token manager back to Default access tokens and save.
Check your work
Press Check my progress. In tenant Audit you can also find tenant.oauth.clients.update for the Token Decoder, oauth.token succeeded with the narrower scope, and oauth.token rejected policy_denied with subject Ben. Logs counts each consent page shown as oauth.authorize succeeded consent_required.
Cleanup
In OAuth > Clients > Token Decoder, confirm Default access tokens, keep Ask once per set of scopes, and remove the
photos.writeassignment. Save.Delete the
lab-tmp-scope-policymanager.Keep Ben and his password.
There is no screen that lists Ava's remembered consents so she could revoke them one by one (G40). Changing a client's settings clears its remembered consent.