1. Docs
  2. Organizations
  3. Delegate Administration

Delegate Administration

Let a customer's own people administer their organization, or one office inside it, without your backend in the loop. Two reserved permissions, each evaluated at a node, decide who runs what.

The Reserved Keys

Delegation is a permission, scoped like any other. Canopy seeds two keys into every Environment with the organizations container on, as system rows in its catalog; you attach them to roles of your own, and the engine evaluates them at a node the same way it evaluates reports.view. In the Developer Console both sit under Canopy capabilities on the Roles page, above your own permissions and tinted apart from them.

canopy:organization.manage, Manage organization: administer the organization the role is held in. Its settings, its authentication policy, its single sign-on connection and verified domains, and its members. It opens every page of the hosted portal.canopy:access.manage, Manage access: add, change and remove role assignments, and invite people, at the node the role is held at and at every node beneath it. Nothing else: the organization's settings stay closed to it. Held anywhere inside the organization, it opens the hosted portal's Access page, and nothing else there: Add access for a member already in the organization, and Invite for anyone by email, both at the places it administers and with the roles its holder may grant there.

A customer cannot create a key inside the canopy: namespace, so nothing of theirs can collide with these, and a permission they define under one of Canopy's own management names (their own identity.manage, say) grants nothing on these routes.

Where Each Key Is Evaluated

Every check names a node, and the engine walks that node's lineage upward: a key held on an ancestor counts, a key held on a sibling does not. The two keys differ only in which node the check names.

Manage organization is checked at the organization's node, whatever node the request touches inside it. Held there, it reaches everything in the organization. Held at one organization, it holds nothing at another.Manage access is checked at the node the write targets. Held at EU Office, it administers EU Office and its teams; a write at UK Office, a sibling, is refused with 403, and so is anything about the organization itself.Holding Manage organization at the organization node implies Manage access everywhere in it, so a tenant's administrator needs nothing more. Held at the organization node on its own, Manage access administers the organization's membership too, without opening its settings. The hosted portal shows Members only to a holder of Manage organization, so that membership work happens in your own screen or over the API.A node outside every organization admits nobody this way. Your API key is bound by neither key, and a full-access key reaches every node as it always has.

The Grant Ceiling

Delegation without a limit is an escalation path: an office administrator who may assign any role could make themselves, or a friend, the organization's administrator. So what an identity may hand out is bounded by what it holds.

An identity may grant a role at a node only when it holds, at that node or above, every permission the role carries, the reserved keys included. Sam holds Manage access and reports.view at EU Office, so Sam may grant Agent (reports.view) there and may not grant Org Admin (canopy:organization.manage) anywhere.The ceiling applies to a new assignment, to a change of role, and to an invitation that carries a role, at the moment it is made. An invitation is checked again when it is read and when it is accepted: if its sender has since been deactivated, or may no longer invite there or grant its role, it is refused with 409 invite.sender_unauthorized or 409 invite.role_not_assignable. It never applies to taking an assignment away.A refused grant answers 403 with assignment.grant_ceiling. Nothing is written.The organization's own administrator, holding Manage organization at the organization node, is the top of the tenant and is not bounded inside it: that key already decides the organization's policy, its sign-in and its arrival roles, and an organization must be able to promote a colleague or hand itself over.Your API key and Console users are not bounded: the developer decides what exists. The Admin Workspace holds its administrators to an allowlist of its own.

The rule needs nothing configured and cannot be misconfigured. Whoever can delegate can only delegate what they have, which is what keeps an office's administrator an office's administrator.

An Office Administrator, Step by Step

Acme is an organization with two offices, EU Office and UK Office, each with teams beneath it. Sam should run access for EU Office. Everything here is the developer's own setup over the API; from then on Sam acts alone.

Make the role

Create a role, Office Admin, and give it canopy:access.manage beside whatever an office administrator needs in your product. The write replaces the role's whole set, so send its other keys alongside.

curl -X PUT https://auth.canopy-io.com/api/v1/roles/{role_id}/permissions \
  -H "X-API-Key: $CANOPY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "permission_keys": ["canopy:access.manage", "reports.view"] }'

Hold it at the office

Sam is already a member of Acme (a membership is a record of its own; the roles are assignments on top of it). Assign Office Admin to Sam at EU Office's node, not at Acme's: the node the key is held at is the node it reaches from.

curl -X POST https://auth.canopy-io.com/api/v1/assignments \
  -H "X-API-Key: $CANOPY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "identity_id": "<sam>",
    "role_id": "<office admin>",
    "node_id": "<eu office>"
  }'

What Sam can do now

Add, change and remove role assignments at EU Office and at every team beneath it, from the hosted portal's Access page or with Sam's own session token.Nothing at UK Office: a write there answers 403. Nothing about Acme itself, its policy, its single sign-on or its member roster, which stay with whoever holds Manage organization.See EU Office and what is beneath it when reading the hierarchy, with Acme shown above it for context and UK Office absent.Hand out only roles whose every permission Sam holds at EU Office. Org Admin is not one of them, so Sam cannot become the organization's administrator, and neither can anyone Sam invites.

To hand Sam the whole organization later, hold Manage organization at Acme's node instead; the access key is then implied everywhere in it. To take EU Office away, remove the assignment; the next check at that node is refused.

In the Hosted Portal

A delegated administrator needs nothing built. They sign in to the hosted portal like any administrator, and the portal shows only what they administer: someone holding Manage access alone sees the Access page and nothing else, where they grant access to members and invite new people straight to the places they administer. In a flat Environment the organization is the only place, so the page does not appear and roles are changed on Members for a member holding one role there. A member holding several roles at the organization is changed over the assignment routes; the portal does not add a second role at the organization node.

The place. The picker in the page header lists the organization's places. A place the reader can see but does not administer, such as the organization above their office, is shown muted and cannot be chosen.Who holds a role there. The list shows every holder at the place, granted there or inherited from above, with Identity, Role, Node, Status and Dates, ten to a page. Granted here and inherited, Granted here and Inherited narrow it by kind of access; All status narrows it to Active, Scheduled or Expired.Add access. The header's Add access opens a dialog. Person searches the organization's members by name or email, or Browse at the end of the field lists them all, eight at a time. Where picks the place, or reads Applies at the place when there is only one. Role lists only the roles the reader may grant there. Effective from and Effective to are optional.Change or remove. A row granted at the place has a menu with Change role, Change dates and Remove access; Remove access asks for confirmation first. An inherited row has no menu: it is changed where it was granted. At the organization node itself the page offers no changes: a role held there is changed on Members, which offers Change role to a member holding one role at the organization. A member holding several roles there is changed over the API's assignment routes.Dates. An Effective from day starts at the beginning of that day and an Effective to day lasts to the end of it, in the reader's own time zone, so access through 31 December includes 31 December.Conflicts. Change role and Change dates send the version the row was read at. If someone changed the grant in the meantime, nothing is overwritten: the portal says that the grant changed since it was opened, refreshes the list, and the reader tries again.Live. The list updates without a reload when access changes anywhere in the organization, whoever made the change.

Building Your Own Admin Screen

The hosted portal renders a delegated administrator's controls from these reads, and so can a screen inside your own product. None of them decides anything: they report what the write routes would accept, so no control you render leads to a refusal.

What they administer

GET /api/v1/organizations/{org_id}/me, with the administrator's own token, answers administers_organization and access_roots: the topmost places where Manage access is held, each with its name, type and the path of names from the organization down to it. Everything the screen shows hangs off this: which places to offer, whether the organization's own pages exist for this person. has_hierarchy is false in a flat Environment, where the organization is its only place. Computed from roles held at or inside the organization, so a role held above every organization opens nothing here.

curl https://auth.canopy-io.com/api/v1/organizations/{org_id}/me \
  -H "Authorization: Bearer <identity access token>"
{
  "data": {
    "administers_organization": false,
    "access_roots": [
      { "node_id": "…", "name": "EU Office", "node_type": "office", "path": ["Acme", "Europe"] }
    ],
    "structure_roots": [],
    "roles_roots": [],
    "has_hierarchy": true
  }
}

What they may do at a place

GET /api/v1/organizations/{org_id}/nodes/{node_id}/grantable-roles: the roles this administrator may grant here under the ceiling. Feed every role picker from it and nothing it offers is refused. The organization's roles list carries the same answer at the organization node as grantable on each role.GET /api/v1/organizations/{org_id}/nodes/{node_id}/access and …/access/summary: who holds a role at the place, directly or inherited from above, with the same filters as the node identities listing.GET /api/v1/organizations/{org_id}/nodes/{node_id}/members: the organization's members as candidates, by name and email only, for an administrator who may not read the full roster.GET /api/v1/organizations/{org_id}/tree: the organization's places pruned to what this administrator may see, for a picker.
curl https://auth.canopy-io.com/api/v1/organizations/{org_id}/nodes/{node_id}/grantable-roles \
  -H "Authorization: Bearer <identity access token>"

The writes

POST, PATCH and DELETE /api/v1/organizations/{org_id}/assignments grant, change and take away a role at the organization node or at a place beneath it, with the administrator's own token. Membership itself is admission, not a role: a member is added and removed through the members routes, and a role at the organization node is an assignment like any other. A grant beneath the organization needs the membership first (409 organization.membership_required); the last administrator's role at the organization node cannot be changed away or removed (409 organization.last_admin). Each write asks the same questions the developer's assignment routes ask: the delegation at the place, the grant ceiling, the organization's own rules. The portal is built on exactly these routes. Every assignment carries a version. Send it back as If-Match on PATCH, and a change somebody made since you read the row answers 409 assignment.version_mismatch instead of overwriting it: read the row again and retry. Removing takes no version.

Next Step

The organization endpoints a delegated administrator calls, the hosted portal, and the membership model are all on the Organizations page.

Environment
API version
v1.0
On this page Was this page helpful?

Tell us how we can improve this guide.