Appearance
Grant access through a Group
In Build in your first Domain you created a Group and added a member to it — but you never used the Group to grant anything. This lesson does. You will grant a Group a relation on a Project, watch every member inherit that access, and then watch it disappear the moment you leave the Group. By the end you will understand how plexsphere delegates access to roles rather than to individuals.
This lesson takes about fifteen minutes.
Before you start
You need a running stack and a logged-in plexctl from Set up your local plexsphere, and you should have finished Build in your first Domain — this lesson assumes you recognise a Project, a Group, a member, and a ReBAC relation. You also need jq on your $PATH.
Recreate the shell environment and capture the Domain and your own user id:
bash
export PATH="$PWD/bin:$PATH"
export PLEXSPHERE_URL=http://localhost:8080
DOMAIN_ID=$(plexctl domain get acme-corp --output json | jq -r '.id')
USER_ID=$(plexctl whoami --output json | jq -r '.subject')Step 1 — Create a Project to share
Make a fresh Project — the resource whose access you will delegate:
bash
PROJECT=$(plexctl project create \
--domain "$DOMAIN_ID" \
--slug group-demo \
--display-name "Group Demo" \
--output json)
PROJECT_ID=$(echo "$PROJECT" | jq -r '.id')
echo "$PROJECT" | jq '{id, domain_id, slug, name}'json
{
"id": "019ecc67-2b3c-7d4e-8f50-1a2b3c4d5e6f",
"domain_id": "019ecc65-8622-7a7f-bfe1-0344c7a22dbd",
"slug": "group-demo",
"name": "Group Demo"
}Step 2 — Confirm you do not hold the access yet
You administer the Domain — but that does not make you a maintainer of every Project in it. maintainer is a relation that has to be granted; administering the Domain gives you management permissions through the tenancy hierarchy, not the maintainer role itself. Ask the authorization engine whether you hold it on the new Project:
bash
plexctl rebac check \
--subject "user:$USER_ID" \
--relation maintainer \
--resource "project:$PROJECT_ID"text
plexctl: rebac check: denied (reason=insufficient_relation, correlation_id=9fdbc8dd-957d-47c3-86eb-c47d2f32a83b)denied, with a non-zero exit. Good — that is the baseline. Now you will grant the relation, but to a Group rather than to yourself.
Step 3 — Build a Group and join it
Create a Group, and capture its id so you can add a member to it:
bash
GROUP=$(plexctl group create \
--domain "$DOMAIN_ID" \
--slug group-demo-operators \
--display-name "Group Demo Operators" \
--source manual \
--output json)
GROUP_ID=$(echo "$GROUP" | jq -r '.id')
echo "$GROUP" | jq '{id, domain_id, slug, display_name, source}'json
{
"id": "019ecc67-3c4d-7e5f-9061-2b3c4d5e6f70",
"domain_id": "019ecc65-8622-7a7f-bfe1-0344c7a22dbd",
"slug": "group-demo-operators",
"display_name": "Group Demo Operators",
"source": "manual"
}Now add yourself — the principal you authenticated as — as a member:
bash
plexctl group member add \
--group "$GROUP_ID" \
--principal "$USER_ID" \
--kind user \
--source manualtext
GROUP PRINCIPAL KIND SOURCE
019ecc67-3c4d-7e5f-9061-2b3c4d5e6f70 019ecc65-9f3a-7c14-8d2b-5f3e0a7b1c40 user manualStep 4 — Grant the Group the access
Now the key move. Grant the maintainer relation on the Project not to a user, but to the Group's member set — written group:<id>#member:
bash
plexctl rebac tuple add \
--project "$PROJECT_ID" \
--resource "project:$PROJECT_ID" \
--relation maintainer \
--subject "group:$GROUP_ID#member"text
ID SUBJECT RELATION RESOURCE CREATED_AT
019ecc67-4d5e-7f60-8172-3c4d5e6f7081 group:019ecc67-3c4d-7e5f-9061-2b3c4d5e6f70#member maintainer project:019ecc67-2b3c-7d4e-8f50-1a2b3c4d5e6f 2026-06-15T18:02:14ZIf the grant returns
Permission Deniedon the first try, wait a couple of seconds and run it again — the Project you just created takes a moment to propagate to the authorization backend.
The #member suffix is what makes this a role grant: it points at "every member of this Group", not at the Group object itself.
Step 5 — Membership grants the access
Run the exact same check as Step 2 — but now you are a member of a Group that holds maintainer:
bash
plexctl rebac check \
--subject "user:$USER_ID" \
--relation maintainer \
--resource "project:$PROJECT_ID"text
DECISION REASON CORRELATION_ID
allowed 788330f3-d36e-4577-b187-eab964129c6eallowed. You did not grant yourself anything — your membership in the Group did. Every other member of group-demo-operators has exactly the same access, and onboarding a new joiner is one group member add, not a tuple per Project.
If it still says
denied, the grant from Step 4 is propagating — wait a moment and run the check again.
Step 6 — Ask the other two questions
rebac check answers one subject-and-resource question at a time. Two companion queries turn it around — what can a subject reach, and who can reach a resource.
First, what can you reach? List the Projects on which you hold maintainer:
bash
plexctl rebac lookup-resources \
--subject "user:$USER_ID" \
--relation maintainer \
--resource-type projecttext
OBJECT
019ecc67-2b3c-7d4e-8f50-1a2b3c4d5e6fThat is the Group Demo Project — the access you inherited through the Group.
Now the reverse, who can reach it? List the users who hold maintainer on the Project:
bash
plexctl rebac lookup-subjects \
--resource "project:$PROJECT_ID" \
--relation maintainer \
--subject-type usertext
OBJECT
019ecc65-9f3a-7c14-8d2b-5f3e0a7b1c40That lists you, the member who holds it. Notice that neither query names the Group: the engine has already expanded membership into concrete resources and subjects, which is exactly what an access review wants to see. Add a second member and they appear in the lookup-subjects answer; remove yourself — as you do next — and you drop out of it.
Step 7 — Leave the Group, lose the access
Group membership is live, not a snapshot. Remove yourself from the Group:
bash
plexctl group member remove \
--group "$GROUP_ID" \
--principal "$USER_ID" \
--kind userremove succeeds silently — it returns no body. Now run the exact same check as Step 5:
bash
plexctl rebac check \
--subject "user:$USER_ID" \
--relation maintainer \
--resource "project:$PROJECT_ID"text
plexctl: rebac check: denied (reason=insufficient_relation, correlation_id=f8da0886-3ddc-430e-9f89-9a1778037a63)denied again. The Project's grant never changed — you simply stopped being a member of the Group it was granted to. Revoking a person's access across every Project a Group governs is a single group member remove.
The re-check can lag a second or two behind the removal, just as the grant did; if it still says
allowed, wait and run it again.
Do this in the Console
Every step above has a browser equivalent in the Console. Open a Project's row on the Projects page and click Manage to reveal its Access grants panel: Grant access picks a Group and grants it a relation on the Project's member set (the group:<id>#member form), and each row's Revoke removes a grant. To confirm a member inherited the access, the panel links to the ReBAC check tool under Tools — the same subject / relation / resource question you ran with plexctl rebac check.
What you learned
- You grant access to roles, not just people. A relation granted to
group:<id>#memberis held by every member of the Group. - Membership is the control point. Adding or removing one member grants or revokes that access across every resource the Group governs — no per-resource tuple churn.
- Administering a Domain is not the same as holding a Project relation. Broad tenancy permissions and specific role relations are separate — administering the Domain did not make you a
maintainer; you granted that relation explicitly. - Authorization is live. ReBAC re-evaluates membership on every check, so access follows the Group in real time.
- You can ask in both directions.
rebac checkanswers one subject-and-resource pairing;rebac lookup-resourcesandrebac lookup-subjectsanswer "what can this principal reach" and "who can reach this" — the queries an access review runs, with Group membership already expanded into concrete resources and subjects.
Where to go next
- Keep learning by doing — Label your first Project defines a Label, grants the two relations that authorize assigning it, attaches it to a Project, and shows how Labels drive selection.
Or pick the quadrant that matches what you need now:
- You have a job to do — the how-to guides, starting with manage Groups.
- You want the exact contract — the
plexctlreference. - You want to understand why authorization is shaped this way — the bounded-context explanations.
- Done with the stack, or want a clean slate — Tear down your local plexsphere removes the cluster, or resets it so you can run these lessons again.