AUTHORIZATION AND POLICY · LAB
Token snapshots, fresh lookups and self-asserted values
Compare a name carried in a token with a department looked up from the directory, see a self-asserted field grant access, and make a missing value fail closed.
Partly readyUses your lab tenant
The lesson
Builds on: Writing rules with attributes, Checking access to each object.
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.
- G21 Group and custom-attribute token claims; directory roles fixed to `member`
- G22 End-user authorization engine (PDP, RBAC/ABAC/ReBAC for application data)
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.
Change Ava's last name while her token is still valid
Recorded as
tenant.users.updatesucceeded about[email protected].Get a new token that carries the new name
Recorded as
oauth.tokensucceeded forlab-printer-appabout[email protected].Ava edits her own profile field
Recorded as
account.profilesucceeded (profile_updated) about[email protected].The permit-shaped rule refuses a subject with no verified address
Recorded as
oauth.tokenrejected (policy_denied) forlab-print-orders.
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
Complete Permit and forbid rules in a token policy for the helpers and
lab-printer-app, and Object and field checks in the tenant's own APIs for the SCIM clients.Create
lab-tmp-policyagain (JWT, default key), assign it tolab-printer-app, leave its script empty, and add one claim mapping:namefrom the attributesubject.name.Define
authorizeandredeemin your shell as in the previous lab, withCLIENT_IDset tolab-printer-app.If
lab-print-ordersdoes not exist, create it in OAuth > Clients: confidential, client credentials only, assignedprints.create. Keep its ID and secret ready. In OAuth > Flow policy, allow the client credentials grant if it is off.Optional, for a richer lookup: in Provisioning, connect the HR simulator through
lab-hr-feedand run the onboarding template briefly, so simulated users have an enterprisedepartment.
Walkthrough
A snapshot. As Ava,
authorize "openid photos.read"andredeem.btl-lab decode "$TOKEN"showsname. Keep this token asOLD:
OLD="$TOKEN"
Now in the portal change Ava's last name to Archer-Lab. Decode OLD again: the old name. Get a new token as Ava and decode it: the new name.
Why it matters: a claim is true as of issue time. A name change does not reach tokens already issued, and a new token helps only because the tenant looks the name up again when it issues one.
A fresh lookup. Get a
lab-scim-readertoken intoSCIMas in the object-checks lab, and ask the directory for Ava's department:
GET$ISSUER/scim/v2/Users/<Ava's
Open in console
GET $ISSUER/scim/v2/Users/<Ava's user ID>?attributes=urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department HTTP/1.1
Authorization: Bearer $SCIMChange her department the way the authoritative source would: send a SCIM PATCH that replaces it as lab-provisioning, or let the HR simulator's lifecycle template move a simulated user and look that user up instead. Look up again: the new value appears at once.
Why it matters: the HR system is the authoritative source for a department. A lookup sees its changes immediately; a token would keep the old value until it expires.
Count the cost. The lookup needed its own client, a request and the directory being available; the token needed nothing. In your notes, choose an approach for three attributes: the display name, the department, and "is this account locked".
Why it matters: freshness is decided attribute by attribute, as the lesson's table does for legal hold, embargo, device and desk.
Break it
A self-asserted attribute. Replace the
lab-tmp-policyscript with a rule that trusts a field the user can edit:
// Deliberately wrong: the last name is a field each user can edit about themselves.
let scopes = [...context.scopes];
if (context.subject.last_name !== 'Legal') scopes = scopes.filter(item => item !== 'prints.create');
return { allow: true, claims: {}, scopes };
In Ava's window open $ISSUER/account, change her own last name to Legal, then request openid prints.create as Ava. prints.create is granted.
Restore: set Ava's last name back to Archer at $ISSUER/account, and clear the lab-tmp-policy script.
Why it matters: a value the subject can edit is only a claim about themselves, like the profile page's desk field. The rule looked right and decided wrongly because its input was self-asserted.
Unknown is not false. Assign
lab-tmp-policytolab-print-ordersas well. A client credentials token has the client as its subject, with no address at all. Try two shapes of the same requirement in the script, requesting a token each time:
read -rs CLIENT_SECRET # lab-print-orders' secret
curl -s -u "<lab-print-orders client ID>:$CLIENT_SECRET" -d grant_type=client_credentials -d scope=prints.create "$ISSUER/oauth/token" | jq '{scope, error, error_description}'
Forbid-shaped:
if (context.subject.email_verified === false) return { allow: false, claims: {} }; return { allow: true, claims: {} };issues the token. The missing value never equalsfalse, so the forbid protects nothing.Permit-shaped:
if (context.subject.email_verified !== true) return { allow: false, claims: {} }; return { allow: true, claims: {} };refuses withunauthorized_client, and Audit recordsoauth.tokenrejected with reasonpolicy_denied.
Restore: assign lab-print-orders back to the default access token manager.
Why it matters: the permit needs a positive answer, so a missing value leaves the request at default deny. That is the lesson's legal hold rule written the safe way round.
Check your work
Press Check my progress. The checks follow the rename, the new token, Ava's own profile edit and the permit-shaped refusal.
Also confirm by hand:
Two decoded tokens for Ava with different
namevalues.Two SCIM answers with different department values.
Cleanup
Set Ava's last name back to
Archerin the portal if step 1 left it changed.Assign
lab-printer-appback to the default access token manager and deletelab-tmp-policy.Pause or cancel any HR simulator run you started.
Missing infrastructure
G21, custom-attribute claims. With department and desk available as token claims, step 1 would use a decision attribute instead of a display name, and the snapshot problem would show up in a real rule.
G22, a decision point with attribute sources. A decision point that can call an attribute source with a per-attribute cache would let the full lab time out the source and see a refusal recorded with the reason
attribute_missing, the source and the policy version, as in the lesson's record.