OAUTH 2.0 · LAB
Delegate photo access without sharing a password
Give an application limited, separately revocable access to Ava's photos, then take that access away while Ava's password keeps working.
ReadyUses your lab tenant
The lesson
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.
Ava approves access for the Token Decoder
Recorded as
oauth.authorizesucceeded (code_issued) about[email protected].The profile request is refused without openid
Recorded as
oidc.userinforejected (insufficient_scope).The profile request succeeds with openid
Recorded as
oidc.userinfosucceeded (userinfo_served).The application's token is revoked
Recorded as
oauth.revokesucceeded (access_token_found).Ava still signs in with her own password
Recorded as
account.sign_insucceeded about[email protected].
Request console
Requests in this lab can be sent from this page to your tenant: open one and choose Send. Fill in the values below first. They stay in this page's memory and are gone when you leave; secrets are never stored or sent anywhere except the request you send.
Setup
This is the first lab of the OAuth track. Later OAuth labs build on the tenant state it leaves behind.
In the tenant portal, open your Lab Photos tenant. For a clean start, reset the lab tenant with the Lab Photos preset (Overview > Reset tenant, then choose the preset). Reset keeps Audit and Logs by default. If you keep your existing tenant instead, confirm that OAuth > Scopes lists
photos.readas common and Users lists Ava Archer ([email protected]).Open Users > Ava Archer > Set password and give her a test password you use only in these labs. Keep it in your shell, not in a file.
Open OAuth > Clients > Token Decoder > View. It is the tenant's built-in public client, and in this lab it plays the printing application. Note its client ID and its redirect URI, which is on your tenant's own host.
Set the shell variables, then press Start on this page.
export ISSUER="https://tenant-<id>.beyondthelogin.dev" # your Lab Photos issuer, from Overview, no trailing slash
export DECODER_ID="<Token Decoder client ID>"
read -rs AVA_PASSWORD # paste Ava's test password, then press Enter
Walkthrough
Open
$ISSUER/token-decoderin your browser. Set Scopes tophotos.readonly and start sign-in. Sign in as Ava on the tenant's own sign-in page. The consent page names "Token Decoder" and lists the description ofphotos.read. Approve.
Why it matters: Ava types her password only into the photo service's own page. The application asking for access never sees it, which is the delegated access problem the lesson starts from.
Read the token response the decoder shows. It has
token_type: Bearer, anexpires_in,scope: photos.readand noid_token. Copy the access token into your shell and decode it.
read -r TOKEN # paste the access token
btl-lab decode "$TOKEN"
The payload shows iss (your issuer), sub (Ava's user ID), aud ($ISSUER/resource), client_id (the decoder's ID), scope and exp.
Why it matters: the token names one application, one area of access and an end time. That is a much smaller relationship than holding Ava's password, which could also delete albums or change her settings.
Use the token to read Ava's profile. Run it in your shell, or open it in the request console.
GET$ISSUER/oidc/userinfo
Open in console
GET $ISSUER/oidc/userinfo HTTP/1.1
Authorization: Bearer $TOKENThe answer is 403 with WWW-Authenticate: Bearer error="insufficient_scope".
Why it matters: whoever holds a bearer token gets only the access it represents. Reading the profile needs openid, which Ava never granted to this application.
Run the decoder again with Scopes
openid photos.read. This time the response also has anid_token. Copy the new access token intoTOKENand repeat step 3: the answer is now200with{"sub": "..."}.
Why it matters: openid asks for the OpenID Connect layer on top of OAuth. The first run gave the application access to photos, but no standardized result it could use to sign Ava in to its own account system.
Take the access away, as the application would when Ava disconnects it. A public client identifies itself with
client_idonly.
POST$ISSUER/oauth/revoke
Open in console
POST $ISSUER/oauth/revoke HTTP/1.1
Content-Type: application/x-www-form-urlencoded
client_id=$DECODER_ID&token=$TOKENThe answer is 200 with {}. Repeat the UserInfo request from step 3: 401 with WWW-Authenticate: Bearer error="invalid_token".
Open
$ISSUER/accountin a private window and sign in as Ava with the same password. It works.
Why it matters: ending the application's access did not touch Ava's password, and nothing else she uses was disrupted. With a shared password, cutting off one application would have meant changing the password everywhere.
Break it
Check the revoked token's contents with the toolkit.
btl-lab verify "$TOKEN" --issuer "$ISSUER" --audience "$ISSUER/resource" --type at+jwt
Every check passes: the signature is valid and exp is still in the future. Yet UserInfo refused this token in step 5. A token's contents alone do not say whether the service still honors it. The Trust boundaries lab returns to this.
Check your work
Press Check my progress. In tenant Audit you can also find:
oauth.authorizesucceededcode_issuedwith actor Ava and client Token Decoder, followed byoauth.tokensucceeded.oidc.userinforejectedinsufficient_scope, thenoidc.userinfosucceededuserinfo_served.oauth.revokesucceededaccess_token_found.account.sign_insucceeded for Ava.
Logs has a summary row for oidc.userinfo rejected invalid_token with status 401.
Cleanup
Keep Ava, her password and photos.read. The next labs use them.