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

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.

  1. Create a token policy that narrows scopes

    Recorded as tenant.oauth.managers.create succeeded.

  2. A scope outside the registration is refused

    Recorded as oauth.authorize rejected (invalid_scope).

  3. Ava signs in and denies the request

    Recorded as oauth.authorize rejected (access_denied) about [email protected].

  4. Ava approves the request

    Recorded as oauth.authorize succeeded (code_issued) about [email protected].

  5. The tenant policy refuses a token Ben approved

    Recorded as oauth.token rejected (policy_denied) about [email protected].

Setup

  1. Press Start on this page.

  2. Open Users > Ben Okafor > Set password and give him a test password for these labs.

  3. Check OAuth > Scopes: photos.read is common, while photos.write and photos.delete are exclusive. The lesson's albums.create plays the same part as photos.write here: access the printer has no need for.

  4. Open OAuth > Clients > Token Decoder > Edit. Set Consent to Ask on every request and assign the exclusive scope photos.write. Do not assign photos.delete. Save.

  5. 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

  1. Open $ISSUER/token-decoder, set Scopes to photos.read, sign in as Ava and approve. The decoder then exchanged the authorization code at the token endpoint with grant_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.

  1. Set Scopes to photos.read photos.delete and start again. The decoder reports error=invalid_scope at 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.

  1. Set Scopes to photos.read photos.write. The consent page lists both. Choose Deny. The decoder reports error=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.

  1. Repeat step 3 and choose Approve. The token response says scope: "photos.read photos.write".

  1. Open OAuth > Clients > Token Decoder, set Access token manager to lab-tmp-scope-policy and save. Repeat step 4: Ava approves both scopes, and the token response now says scope: "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.

  1. In the Token Decoder's settings, set Consent to Ask once per set of scopes and save. Request photos.read twice in a row as Ava: the second time there is no consent page. Request photos.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

  1. Change the lab-tmp-scope-policy script so the tenant refuses Ben, and save.

return {allow: context.subject.email !== '[email protected]', claims: {}};
  1. In the Token Decoder, tick Ask me to sign in again, request photos.read, sign in as Ben and approve. The token endpoint answers invalid_grant with "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

  1. In OAuth > Clients > Token Decoder, confirm Default access tokens, keep Ask once per set of scopes, and remove the photos.write assignment. Save.

  2. Delete the lab-tmp-scope-policy manager.

  3. 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.

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