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

Follow a relationship graph to a yes or a no

Planned: store relationship facts for the photo library and follow paths to decisions. Today: query your tenant's real group and manager relationships in both directions with SCIM.

PlannedUses your lab tenant

The lesson

Builds on: Checking access to each object.

New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.

Planned. The core of this lab waits on platform features that are not built yet. The planned walkthrough shows exactly how it will run; Do today is a real exercise you can do now.

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

The tenant has no relationship-based authorization for application data (G22) and no photo API to protect (G3). Group membership and the SCIM manager attribute are real relationship data, but no access decision reads them. The planned walkthrough shows the full lab as it will run; Do today practices the same questions on the real data.

  1. Complete Object and field checks in the tenant's own APIs for the SCIM clients lab-scim-reader and lab-provisioning, with SCIM turned on.

  2. In Groups, create lab-tmp-sports-desk and add Ben and Cora.

  3. Note the user IDs of Ava, Ben and Cora and the group's ID. In this lab Cora plays Maya the owner, Ava plays Lena the contributor, and Ben plays Omar the editor.

Planned walkthrough

These requests will run once the photo library API and its decision point exist. TOKEN will hold a client credentials token for lab-photo-api, which may write facts and ask questions for this tenant only.

  1. Store the lesson's facts, one tuple each:

POST $ISSUER/lab-api/photos/relationships
Authorization: Bearer $TOKEN
Content-Type: application/json

{"writes":[
 {"object":"album:4410","relation":"owner","subject":"user:<Cora's ID>"},
 {"object":"album:4410","relation":"contributor","subject":"user:<Ava's ID>"},
 {"object":"group:sports-desk-editors","relation":"member","subject":"user:<Ben's ID>"},
 {"object":"library:sports","relation":"editor","subject":"group:sports-desk-editors#member"},
 {"object":"album:4410","relation":"parent","subject":"library:sports"},
 {"object":"photo:9001","relation":"parent","subject":"album:4410"}]}

The answer returns the relationship version the write created.

  1. Read the relation rules in the portal: owner implies editor, editor implies contributor, contributor implies viewer; relations flow from library to album to photo; photo.view needs viewer, photo.upload contributor, photo.delete editor.

  2. Ask whether Ava may view photo 9001:

POST $ISSUER/lab-api/access/v1/evaluation
Authorization: Bearer $TOKEN
Content-Type: application/json

{"subject":{"type":"user","id":"<Ava's ID>"},"action":{"name":"photo.view"},"resource":{"type":"photo","id":"9001"}}

The answer is a permit with the path photo:9001, album:4410, user:<Ava's ID>.

  1. Ask whether Ben may delete photo 9001. A permit, with the five-step path through the group and the Sports library.

  2. Ask whether Ava may delete photo 9001. A deny: Ava is a contributor, and no path reaches her with editor.

  3. Remove Ben's group membership and ask step 4 again. A deny, and the explanation shows which fact was missing.

  4. The reverse question, everything Ava may view:

POST $ISSUER/lab-api/access/v1/search/resource
Authorization: Bearer $TOKEN
Content-Type: application/json

{"subject":{"type":"user","id":"<Ava's ID>"},"action":{"name":"photo.view"},"resource":{"type":"photo"}}

Only album 4410's photos come back, with the index version the answer used.

Do today

The same questions on real relationship data. Get a lab-scim-reader token into SCIM as in the object-checks lab.

  1. From a subject to its objects: which groups does Cora belong to?

GET$ISSUER/scim/v2/Users/<Cora's Open in console
GET $ISSUER/scim/v2/Users/<Cora's user ID>?attributes=groups HTTP/1.1
Authorization: Bearer $SCIM

Why it matters: this is the reverse question, starting from a person and following every membership outward.

  1. From an object to its subjects: who is in the group?

GET$ISSUER/scim/v2/Groups/<lab-tmp-sports-desk Open in console
GET $ISSUER/scim/v2/Groups/<lab-tmp-sports-desk ID> HTTP/1.1
Authorization: Bearer $SCIM

Why it matters: the forward direction. A relationship system keeps both directions searchable, because checks and lists start from different ends.

  1. The same membership asked as a filter over all users:

curl -s -G -H "Authorization: Bearer $SCIM" "$ISSUER/scim/v2/Users" \
  --data-urlencode 'filter=groups.value eq "<lab-tmp-sports-desk ID>"' --data-urlencode 'attributes=userName' | jq '.Resources[].userName'

Why it matters: the directory answers from an index of memberships rather than reading every user, which is what a list page needs.

  1. Add a fact with an object, a relation and a subject. Get a lab-provisioning token into SCIM and make Cora Ava's manager:

PATCH$ISSUER/scim/v2/Users/<Ava's Open in console
PATCH $ISSUER/scim/v2/Users/<Ava's user ID> HTTP/1.1
Authorization: Bearer $SCIM
Content-Type: application/scim+json

{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager","value":{"value":"<Cora's user ID>"}}]}

Then ask for Cora's direct reports with the filter urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value eq "<Cora's user ID>", in the same form as step 3. Ava comes back.

Why it matters: "Cora manages Ava" is a stored fact queried both ways, the raw material of relationship-based access, even though no decision reads it yet.

  1. Write Ava, Ben, Cora, the group and the manager fact as tuples in the lesson's notation, such as group:lab-tmp-sports-desk#member@user:ben, and draw the graph.

Why it matters: with the facts written down, every access question becomes a search for a path, and every missing path is a no.

Break it

  1. Planned: a request with no path is denied, and deleting one fact removes exactly the access that depended on it at the next check.

  2. Today: ask Lab Mail for your Lab Photos group with the same token, GET $ISSUER2/scim/v2/Groups/<lab-tmp-sports-desk ID>. It is refused, because the token and the relationship data both belong to one tenant.

Check your work

No automated checks: this lab is planned. In the tenant's Audit and Logs, look for the SCIM reads and the manager change made by lab-provisioning, and keep your tuple list and drawing.

Cleanup

  • Clear Ava's manager with a SCIM PATCH that removes the attribute.

  • Delete the group lab-tmp-sports-desk.

Missing infrastructure

  • G3 and G22, the photo library API with a relationship store. A per-tenant store of relationship tuples with relation rules, a check endpoint that returns the deciding path, a reverse search endpoint backed by an index with a version, and decision records in tenant Audit. Once it exists, the planned walkthrough runs as written, and its steps get automated checks on the decision records.

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