Skip to main content

Organizations, persons and grants

A person can do something in OktoID only because they hold a grant: a bundle of permissions, for one organization and everything beneath it. Nothing the identity provider says about the person (a group, a role, an attribute) gives them any authority. Signing in proves who someone is; their grants decide what they may do.

This page explains the parts and the rules that connect them. The requests that put them to work, from a fresh stack to a second administrator signing in, are in Install and sign in.

Organizations​

Organizations form a tree. Each one has a path made of the slugs above it, such as /oktoid/acme/branch, and an id (a UUID) that never changes.

  • The top of the tree is the anchor. The setup run creates it from the deployment's answer file; on a local stack it is /oktoid.
  • An organization is created with POST /api/v1/subjects, beneath the organization you act for, or beneath a parentPath inside it.
  • A slug is lowercase letters, digits and hyphens, 1 to 63 characters, starting and ending with a letter or a digit. It is unique among its siblings.

Organizations listed in the answer file are created by the setup run on every deploy if they are missing.

Persons​

A person is someone who signs in. They are registered with POST /api/v1/persons and sit beneath the organization that registered them: a person registered for acme has the path /oktoid/acme/<their id>.

  • A person is always a leaf. Nothing can be created beneath a person.
  • A person's path ends in their id, never their name. Paths appear in logs and audit records, and a name there would be personal data in places that are never erased.
  • Names and email address are personal data. They are stored encrypted under a key that belongs to that person alone, are never logged, and disappear from every reply once the person is erased. Erasing a person destroys that key, which leaves the stored values unreadable. This release has no request that erases a person.
  • "invite": true creates the person's account in the staff realm of the identity provider and sends them an invitation. Before the account can sign in, its holder must verify the address, set a password, and set up a second factor with an authenticator app. Without invite, the person exists in OktoID but has no account to sign in with.

Registering a person gives them no authority. Until someone grants them a bundle, they can sign in and do nothing.

Bundles​

A bundle is a named set of permissions. This release has five, created by the setup run. No request creates or changes a bundle.

BundleHoldsWho holds it
ENTITY_ADMINRunning an organization: create and read organizations, create and read persons, and create, read and revoke grants. Nothing of the trust treeAn organization's administrators, and the root account at the anchor unless the answer file names another bundle
ORGANIZATION_CLIENTCreate and read organizationsMachine clients, unless the answer file names another bundle for one
TRUST_ANCHOR_ADMINGoverning the trust tree: put an organization forward, admit it, approve publication, and read accreditations, entity statements and organizationsThe governance authority's staff who decide admissions
ACCREDITATION_OFFICERPut an organization forward, and read accreditations, entity statements and organizations. It cannot admit or approve publicationStaff who prepare admissions for someone else to decide
SOLE_ADMINEverything in ENTITY_ADMIN and TRUST_ANCHOR_ADMIN togetherThe root account on a local stack, where one person runs and governs. The setup run refuses it for the root account in a staging or production deployment

Running an organization and governing the tree are kept apart on purpose. A holder of ENTITY_ADMIN cannot admit anyone, and because delegation only narrows, cannot grant a bundle that can. What the trust-tree permissions are for is in The trust tree.

The permission definitions in @oktoid/contracts are the authority on what each bundle holds.

Grants​

A grant says: this person holds this bundle for this organization. It gives the bundle's permissions over the organization and everything beneath it, and nothing above or beside it.

  • A grant is made with POST /api/v1/grants, naming the person (granteeId), the organization (organizationId) and the bundle.
  • A person holds at most one active grant per organization. To change the bundle, revoke the grant and make a new one.
  • A person may hold grants for several organizations, and acts for one of them at a time.
  • GET /api/v1/grants lists the grants for organizations inside your own, filtered by organization, grantee or status.
  • Every grant and every revocation is written to the audit record, with who did it.

A grant gives authority, not visibility elsewhere. Anything outside the organization you act for answers 404, exactly as something that does not exist would. A refusal never tells you whether the thing exists.

Machine clients hold grants too: one each, for the organization the answer file says it acts for, made by the setup run. A grant made through the API is always for a person.

Delegation only narrows​

You can grant only what you hold yourself, and only inside your own organization. A grant is refused unless:

  • every permission in the bundle is one your own grant has, and
  • the organization is the one you act for, or beneath it.

So an administrator of /oktoid/acme can make another administrator of /oktoid/acme or of /oktoid/acme/branch, but not of /oktoid, and cannot hand out a bundle larger than their own. A refused grant answers 404, the same answer as for an organization or person that does not exist.

The same rule applies to revoking: you cannot revoke a grant larger than your own, so a narrower administrator cannot lock out a broader one.

Acting for an organization​

Every request a person makes names the organization they act for, in the header

Oktoid-Acting-For: <the organization's id>

For that request, the person's reach is that organization's subtree, and their permissions are those of the bundle on their grant there.

  • Without the header, a person's request is refused with 403.
  • With an organization they hold no grant for, the request is refused with the same 403, whether or not the organization exists.
  • Machine clients send no header. They act for the one organization their grant names.

To learn which organizations you can act for, ask GET /api/v1/me. It is the one request that acts for no organization: it takes no Oktoid-Acting-For header, ignores one if sent, and needs no permission. It answers your own active grants, each with the organization's id (the value for the header), its path and the bundle:

{"grants":[{"organizationId":"<a UUID>","path":"/oktoid/acme","bundle":"ENTITY_ADMIN"}]}

It never shows anyone else's grants. If you hold none, the list is empty rather than an error. It reads your grants afresh on every call, so a grant made or revoked shows there at once, even while a revoked grant can still authorize requests (see Revoking a grant). On a local stack, pnpm oktoid login prints the same list when you sign in (Install and sign in, step 5).

Revoking a grant​

POST /api/v1/grants/{id}/revoke

The grant's status becomes revoked, and the change is audited. Revoking a grant that is already revoked answers the same revoked grant and changes nothing.

A revocation takes effect within one token lifetime: at most five minutes. The gateway remembers what a signed-in person may do for a short time, never longer than five minutes and never past the expiry of their access token. Until that memory expires, a revoked grant can still authorize requests. Plan for that window when you remove someone's access in a hurry: revoke the grant, and expect up to five minutes of residual access.

Who can revoke whom​

Revoking needs the same three things as granting: the revoke permission (in this release only ENTITY_ADMIN holds it), a grant for an organization that is the one you act for or beneath it, and a bundle no larger than your own. Who made the grant is not checked. In practice:

  • Anyone who holds the revoke permission can revoke their own grant. That includes the last administrator of an organization, who then leaves it with none. The root account is the exception in effect: the next setup run restores its grant (see The root account).
  • A peer administrator can revoke the administrator who appointed them. If an administrator of /oktoid/acme appoints a second administrator of /oktoid/acme, each can revoke the other.
  • An administrator cannot revoke a grant above their own organization. The administrator of /oktoid/acme that the root account appointed cannot revoke the root account's grant at /oktoid.

Revoking a grant does not revoke the grants it was used to make​

When a person revokes a grant, the grants its holder made stay active. If an administrator of /oktoid/acme appointed others and their own grant is then revoked, every grant they made keeps working. Each grant names who made it (grantedBy in the reply of GET /api/v1/grants), and every grant and every revocation is in the audit record with who did it, so the grants a removed administrator made can be found and revoked one by one.

A revocation the platform triggers itself, rather than a person, cascades. It also revokes the grants made under the revoked grant. The one such revocation in this release is the setup run's, when the answer file gives a machine client a different bundle: its old grant is revoked and a new one made, both audited.

The root account​

The root account is the first staff account, created by the setup run for the mailbox the answer file names. It holds ENTITY_ADMIN at the anchor, and every other grant descends from it.

The setup run restores the root account's grant. If the grant is revoked or missing, the next setup run makes it again. On a local stack, that is the next pnpm stack:up. The setup run then:

  • records the new grant in the audit record, as any grant;
  • reports a root-grant-restored finding in its output.

Revoking the root account's grant is therefore not a way to remove the root. To stop a compromised root account from being used, change its credentials at the identity provider.