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

IDENTITY FUNDAMENTALS · LAB

Least privilege for Ben, enforced on the server

Give Ben a read-only management role, send the hidden lock request directly and watch the server deny it, then grant exactly one more permission and take it away again.

Partly readyUses your lab tenant

The lesson

Builds on: Proving control of an account.

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. Create a role with one permission

    Recorded as tenant.roles.create succeeded.

  2. Assign a management role to Ben

    Recorded as tenant.users.management_roles.assign succeeded about [email protected].

  3. See Ben's direct lock request denied

    Recorded as tenant.users.lock rejected about [email protected].

  4. Lock Cora after Ben gains exactly that permission

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

Setup

The tenant's own management portal is a real example of the lesson: a permission catalog, roles that group permissions, and a server that checks every request. Ben Okafor plays the help desk.

  1. On this lab page choose Lab Photos and press Start.

  2. On Ben's record choose Set password, store it in your password manager, and keep the issuer in the shell:

ISSUER=https://tenant-<id>.beyondthelogin.dev
  1. Roles > Create role Directory viewer with only the permission to read tenant users (tenant.users.read).

  2. On Ben's record open Management roles and assign Directory viewer. Changing Ben's roles ends any sessions he has.

Walkthrough

  1. In a private window sign in as Ben at $ISSUER/manage. Because Ben now holds a management role, the tenant asks for a second step. If he has none yet, register your authenticator app for him when asked. Ben sees Users, with no Create, Lock or Delete.

Why it matters: the interface hides what Ben cannot do. That is usability, not enforcement.

  1. Write down the access decision you are about to test. Subject: Ben. Resource: Cora's record. Action: lock (tenant.users.lock). Context: a full signed-in session with a second step.

  2. In DevTools > Application > Cookies, copy the value of __Host-btl-oauth-session for your tenant host and keep it out of your shell history. It belongs to a test user and ends when you sign Ben out in Cleanup.

read -rs BEN_SESSION
  1. Read what Ben is allowed to read, and keep Cora's ID and version:

curl -s "$ISSUER/api/auth/tenant/users" -H "Cookie: __Host-btl-oauth-session=$BEN_SESSION" | jq '.users[] | {id, email, version}'
CORA_ID=<Cora's id>
CORA_VERSION=<Cora's version>
  1. Send the hidden action directly:

lock() { curl -i -X POST "$ISSUER/api/auth/tenant/users/lock" -H "Origin: $ISSUER" -H "Content-Type: application/json" \
  -H "Cookie: __Host-btl-oauth-session=$BEN_SESSION" \
  -d "{\"id\":\"$CORA_ID\",\"version\":$CORA_VERSION,\"command_id\":\"$(node -p 'require("crypto").randomUUID()')\"}"; }
lock

Expected: 403 with "code":"access_denied".

Why it matters: the service checked the action against Ben's current role assignments on this request. Hiding the button was never the control.

  1. In Audit find tenant.users.lock rejected, with Ben as actor and Cora as subject.

Why it matters: a denied decision is still a decision worth recording, with its subject, resource and action.

  1. Least privilege: Roles > Create role Account locker with only the lock and unlock user permissions. Assign it to Ben as well. His session ends again, so sign in as Ben once more, copy the new cookie into BEN_SESSION with read -rs, and run lock. Expected: 200, and Cora is locked. Audit shows tenant.users.lock succeeded with Ben as actor.

Why it matters: roles group permissions. Ben gained exactly one capability, not "administrator".

  1. As yourself, unlock Cora and refresh CORA_VERSION from the list in step 4. Remove Account locker from Ben, sign in as Ben again, copy the new cookie and run lock. Expected: 403 again.

Why it matters: the decision uses Ben's current assignments, not what he could do a few minutes ago.

Planned walkthrough

These steps need a per-tenant photo library API with its own authorization engine (G22). They show the lesson's album example exactly as it will run.

  1. Create album 42 owned by Ava and share it read-only with Ben, then write the policy "owner may delete, invited viewer may read".

  2. As Ava, delete a photo in album 42. Allowed:

curl -i -X DELETE "$ISSUER/lab-api/photos/albums/42/photos/7" -H "Authorization: Bearer $AVA_TOKEN"
  1. As Ben, send the same request. Expected: 403, and a decision log entry naming subject, resource, action and the rule that applied.

  2. As Ava, change the album number to 43, an album she does not own. Expected: 403. Knowing an identifier never grants access to what it names.

  3. Add an attribute rule: downloading unpublished photos requires department Communications and a managed device. Cora's department came from HR in the Establishing an identity lab; Ben has none, so only Cora's download is allowed.

Break it

  1. Run the request from step 5 with no Cookie header. Expected: 401. Compare it with the 403: 401 asks "who are you?", while 403 says "we know who you are, and the answer is no".

  2. While Ben still holds Account locker in step 7, run lock a second time with the old CORA_VERSION. Expected: 409. The server also refuses to act on stale information about the resource.

Check your work

Press Check my progress. It looks for:

  • tenant.roles.create succeeded.

  • tenant.users.management_roles.assign succeeded for Ben.

  • tenant.users.lock rejected for Cora (Ben without the permission).

  • tenant.users.lock succeeded for Cora (Ben with Account locker).

Cleanup

  1. Make sure Cora is unlocked.

  2. Remove all management roles from Ben and delete Account locker. Keep Directory viewer unassigned if you like.

  3. Sign Ben out at $ISSUER/account so the copied cookie stops working, then run unset BEN_SESSION.

Missing infrastructure

  • G22 End-user authorization engine. There is no policy decision point or sample photo service with albums, owners and invited viewers. Once it exists, the planned walkthrough evaluates real RBAC and attribute rules against real album requests and shows each decision.

  • G21 Group and custom-attribute token claims. Department and device attributes cannot reach tokens today, so an application could not receive the attributes the planned attribute rule needs.

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