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

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.

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. Change Ava's last name while her token is still valid

    Recorded as tenant.users.update succeeded about [email protected].

  2. Get a new token that carries the new name

    Recorded as oauth.token succeeded for lab-printer-app about [email protected].

  3. Ava edits her own profile field

    Recorded as account.profile succeeded (profile_updated) about [email protected].

  4. The permit-shaped rule refuses a subject with no verified address

    Recorded as oauth.token rejected (policy_denied) for lab-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

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

  2. Create lab-tmp-policy again (JWT, default key), assign it to lab-printer-app, leave its script empty, and add one claim mapping: name from the attribute subject.name.

  3. Define authorize and redeem in your shell as in the previous lab, with CLIENT_ID set to lab-printer-app.

  4. If lab-print-orders does not exist, create it in OAuth > Clients: confidential, client credentials only, assigned prints.create. Keep its ID and secret ready. In OAuth > Flow policy, allow the client credentials grant if it is off.

  5. Optional, for a richer lookup: in Provisioning, connect the HR simulator through lab-hr-feed and run the onboarding template briefly, so simulated users have an enterprise department.

Walkthrough

  1. A snapshot. As Ava, authorize "openid photos.read" and redeem. btl-lab decode "$TOKEN" shows name. Keep this token as OLD:

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.

  1. A fresh lookup. Get a lab-scim-reader token into SCIM as 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 $SCIM

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

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

  1. A self-asserted attribute. Replace the lab-tmp-policy script 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.

  1. Unknown is not false. Assign lab-tmp-policy to lab-print-orders as 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 equals false, so the forbid protects nothing.

  • Permit-shaped: if (context.subject.email_verified !== true) return { allow: false, claims: {} }; return { allow: true, claims: {} }; refuses with unauthorized_client, and Audit records oauth.token rejected with reason policy_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 name values.

  • Two SCIM answers with different department values.

Cleanup

  • Set Ava's last name back to Archer in the portal if step 1 left it changed.

  • Assign lab-printer-app back to the default access token manager and delete lab-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.

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