Authority
How Stem decides who may read, write and administer a resource, using a graph of signed grants and revocations with four ordered access levels, delegation, groups, late-bound two-pass evaluation and inheritance down the placement tree, and how this replaces Capabilities and the visibility field.

Part of Stem. This page defines authority: the signed statements that confer access, the levels of access, how statements compose and are cut, and how a peer evaluates them to answer "may this principal do this to that node". Authority is a graph that is separate from placement. The roadmap's phrase is that the authority graph is critical and the placement graph is for naming; this page is the authority graph.

Three words

A grant is a signed blob stating that an audience holds an access level over a subject. An access level is one of four ordered words. A revocation is a signed blob that cuts a grant. There is no other kind of authority statement. Public publishing, private spaces, sharing with one person, share links, group membership, agents, devices and sites are all grants, and HM24's Capability, its visibility field and its siteUrl trust are all replaced by grants.

The model is the Keyline proposal from Ink & Switch, which the team adopted as its foundation for private document hierarchies: authority is a graph whose nodes are principals, groups and resources and whose edges are signed delegations at an access level; access composes along a path and is capped at the lowest level on the path; delegations are late-bound; revocations cut edges; admins keep their revocation power forever. Stem writes that model as two blob types and one evaluation procedure.

Grants

A Grant has four parts.

    subject: what is covered. A node, by default with its whole subtree in the placement tree, or exactly that node when exact is set; or a group. A subject whose node is omitted names the space root and covers the whole space.

    audience: who receives the access. One of the five audience kinds: everyone, a key, a group, a bearer secret, or the readers of another node.

    access: one of sync, read, write, admin.

    signer: the principal whose authority this grant spends. The signer must hold, at evaluation time, at least access over the subject. proof names the grant through which the signer holds it, as a hint for fetching; evaluation does not trust the hint.

Optional expires ends the grant at a time by the evaluating peer's clock. This is the one place a clock is consulted, and it is the evaluating peer's own clock, never a timestamp in a blob. Optional label is a public note.

Access levels

Level

May

Granted today to

sync

Hold and relay the subject's blobs. Reserved for encrypted content; until encryption exists it implies nothing a reader cannot do and is used only to mark a declared site peer as an authority peer.

site peers

read

Read the subject's state and everything it covers; list its readable children; comment on it (a comment is the commenter's own resource whose readers follow the target).

members, invited readers, everyone (public)

write

Everything read allows, and publish Node, Change and Snapshot blobs for the subject and create children under it.

collaborators, agents, writers

admin

Everything write allows, and issue grants and revocations over the subject at any level up to admin.

owners, trusted devices, organisers

The levels are totally ordered: sync < read < write < admin. A principal's level over a node is the highest level any live path in the graph gives it. The space owner, the key that is the space, holds admin over the space root permanently and without a grant: it is the origin of every path in the space.

Operations by level

Operation

sync

read

write

admin

Receive the node's blobs over sync

yes

yes

yes

yes

Read the node's state, facts and readable children


yes

yes

yes

Publish a comment targeting the node


yes

yes

yes

Publish a Node blob for the node (edit, move, delete)



yes

yes

Create a child node (publish a creating Node blob naming this node as parent)



yes

yes

Issue a grant over the node at up to one's own level




yes

Revoke a grant over the node issued by anyone




yes

Revoke a grant one issued oneself

any issuer




Renounce a grant one received

any delegate




The "create a child" row is how other people write into a space they do not own: any key holding write on a node may publish a creating Node blob under it, naming the owner in space, and the new node belongs to the owner's space without the owner signing anything. The same holds for a device or agent key the owner has granted write.

A write holder cannot issue grants. This is a deliberate narrowing of Keyline, where any holder may re-delegate: Seed's experience with path-scoped capabilities was that silent re-delegation makes a space's membership unknowable to its owner. A writer who wants to share asks an admin, or the owner makes them an admin of a subtree.

Subjects and inheritance

A grant on a node covers the node and every node placed under it, unless exact is set. Coverage follows placement at evaluation time: a node moved under a covered node becomes covered, a node moved out stops being covered. Grants are therefore evaluated against the placement tree as it is now, never against where a node was when the grant was signed.

Readers compose the same way, as described in Privacy: a node with access mode inherit has its parent's readers plus the audiences of grants that cover it; a node with own has only the grants that cover it; a node with target has the readers of the node it targets.

A grant on a group makes the group's members. A principal is a member of group G when it holds a live grant whose subject is G at read or above. An admin on G may add and remove members by issuing and revoking such grants. A grant whose audience is {kind: group, group: G} then means "every live member of G".

Groups

A Group is a permanode: a signed blob with a random nonce whose CID is the group's id and whose signer is its owner and permanent admin. It has no members of its own; membership is grants with the group as subject. The roadmap records the decision to want a group concept, "one capability granting several keys at once", and to prefer a permanode per space whose admins are permanent with admin removal done by rotating the permanode. Stem generalises that: a space is already a group (its root node, with the space key as permanent admin), and any owner or admin may create further groups for teams, sharing circles or roles.

Groups are flat at issuance for evaluation purposes: a grant to a group is expanded to the group's live members when readers are materialised, and a group may itself be a member of another group, with nesting bounded to a depth the daemon enforces (two levels in the first implementation). This is the "flatten at issuance, cap nesting" position from the permissions investigation.

Admin rotation

Admins are forever in the sense that a principal with admin over a node retains its revocation power over everything under its admin reach. So removing an admin is not a revocation of one grant but a rotation: the owner (or a higher admin) creates a new group, grants it over the subtree, re-grants the remaining admins and members through the new group, and revokes the grant that gave the old group its authority. Every path through the old group goes dead at once. The owner key itself cannot be rotated out of its own space; that is what owning a space means.

Delegation

A grant whose signer is not the space owner spends authority the signer received from another grant. Delegation is capped: the issued level is at most the issuer's level over the subject, and the subject is at most the issuer's subject (a node in the issuer's covered subtree, or the same group). A grant that exceeds its issuer's authority is not invalid forever; it is stashed and becomes live if the issuer's authority grows to cover it. This is late binding: a grant works while its issuer has sufficient authority, stops working when that authority disappears, and recovers when another route restores it.

The proof field tells a fetching peer which grant to ask for first so that authority arrives before the blobs that rely on it. It is not consulted during evaluation, because the graph may contain a shorter or newer path than the one the signer knew about.

Revocation

A Revocation names one grant by CID. It is valid when signed by:

    the grant's signer (retraction);

    the key the grant was issued to, when its audience is a key (renunciation);

    any principal with admin over the grant's subject (administrative revocation).

A revocation does not delete anything. The grant blob remains in the store and in history; the evaluation treats the edge as cut. A revocation cannot be undone, but a new grant can be issued. Timestamps on grants and revocations are advisory: a revocation cuts the grant whenever it arrives, and a Node blob signed under the grant is re-evaluated when the revocation lands. Blobs that lose their authority are stashed, not deleted, so a mistaken revocation loses no data; a new grant unstashes them.

What revocation means for bytes already delivered is stated in Privacy: honest peers stop serving, the disclosure ledger says who already holds them, and nothing is un-sent.

Evaluation

The level a principal holds over a node is computed by two passes over the space's grants and revocations, and the result does not depend on the order in which the blobs arrived.

    Positive pass. Build the graph from every grant, ignoring revocations and expiry. Starting from the owner (permanent admin over the space root), walk edges forward: an edge from signer to audience at level L over subject S is traversable when the signer's level over S in this pass is at least L. Record, for every principal, its admin reach: the subjects over which it holds admin in this pass. This pass exists so that an admin's power to revoke is not itself subject to the revocations it issues.

    Live pass. Remove every grant that has a valid revocation (validity judged against the admin reach from the positive pass) or has expired by the local clock. Walk the remaining graph the same way from the owner. The level a principal holds over a node is the highest level at which it is reached over any subject that covers the node (the node itself or an ancestor, respecting exact).

Readers are then materialised per node, and every blob in the node's state is mapped to the node, as Privacy describes. Evaluation reruns for the affected subtree whenever a grant, a revocation, a Node blob that changes placement or access, or a group change is indexed. Because the procedure is deterministic over the set of blobs held, two peers holding the same blobs agree, which is the property sync needs.

Example

Alice owns a space. She publishes G1 = Grant{subject: root, audience: everyone, access: read} (her space is public) and G2 = Grant{subject: docs, audience: key(Bob), access: admin}. Bob publishes G3 = Grant{subject: docs/drafts, audience: key(Carol), access: write, proof: G2}. Carol publishes a Node blob creating docs/drafts/plan.

Positive pass: Alice has admin over root; G1 gives everyone read over root; G2 gives Bob admin over docs; G3 is traversable because Bob holds admin over docs which covers drafts, so Carol has write over drafts. Live pass: nothing revoked, same result. Carol's Node blob is authorized because she holds write on the parent drafts.

Alice later publishes R1 = Revocation{grant: G2}. Live pass: G2 is cut; G3 is now unreachable because Bob no longer holds admin over docs; Carol's node and any Node blob she published are stashed, not deleted. The documents are still readable by everyone through G1. If Alice then grants Bob admin again, G3 becomes live and Carol's blobs are unstashed.

Agents, devices and sites

Agents. An agent key receives write on the subtree it is meant to work in, usually with expires, and read is implied. Today's AGENT role let a key act as the issuer for the whole space with no scope and no expiry; in Stem that is write on the space root, and it is the owner's choice to grant so much. An agent cannot issue grants, which is the point: the owner stays the only source of authority. Agents are described further in Agents and notifications.

Devices. Today every blob is signed by the account key, which lives on every device. Stem keeps that as the default, and adds the option of device keys: the account key grants a device key admin over the space root, the device then signs Node, Change, Grant and Revocation blobs with its own key, and losing the device means revoking one grant instead of abandoning the account. A device grant is a grant like any other; the account key remains the permanent admin.

Sites. Today a site's authority over a space is a siteUrl string in the home document plus an HTTPS lookup, and the roadmap wants it to become a signed relationship. In Stem the space root's attributes name the site's URL and peer id, and the owner issues Grant{subject: the space root, audience: key(site peer's account), access: sync}. The site is then an authority peer for the space, may hold and serve every blob of the space including private ones, and loses that standing with one revocation. Without the grant the URL is decorative.

Authentication versus authority

Authentication is proving which account a connection or request speaks for; authority is what that account may do. They are different mechanisms and must not be confused. A peer authenticates to another with the Authenticate RPC, a signature by the account key over the two peer ids and a fresh timestamp, exactly as today's ephemeral capability does, and the binding lasts for the connection. An HTTP client authenticates with a bearer token obtained the same way. Once authenticated, every read is evaluated against the account's level over the node that covers the blob, and every write is evaluated against the signer of the blob, which may be the account or a key it delegated to. A write never needs a token: its authority is in the blob.

Stash and re-evaluation

A Node, Change or Snapshot blob whose signer does not currently hold the required level is stored and stashed with reason PermissionDenied, exactly as today's unauthorized Refs are. A grant whose signer lacks the authority it spends is stashed the same way. When any grant, revocation or group change is indexed, the affected subtree is re-evaluated and stashed blobs whose signer is now authorized are applied. This is what makes arrival order irrelevant: a writer's blobs may reach a peer before the grant that authorizes them, and the outcome is the same.

Today (HM24)

Today

Stem

Capability: signed only by the owner, roles WRITER and AGENT, path prefix, no expiry, no revocation

Grant: signed by anyone with authority, four levels, node or group subject, optional expiry, revocable

Visibility field on Ref and Comment, two values

Grant{audience: everyone} for public; its absence for private; any audience in between

Read requires a root-scoped WRITER over HTTP but any-path WRITER over peer sync

read level, evaluated identically on every surface

AGENT: act as the owner everywhere, forever

write on root, or on a subtree, with expires

siteUrl plus HTTPS lookup confers private-blob access

sync grant to the site peer's account

One hop of AGENT delegation, path by breadcrumbs

Delegation to any depth along the graph, capped by level and subject

Revocation reserved in the proto, unbuilt

Revocation blob, late-bound evaluation

Groups: retired in 2024

Groups as permanodes, membership by grant

The shipping model is documented in Permissions and Capability. The direction is in Where this is going under Permissions.

Open questions

    Open: whether write holders should be allowed to delegate read (share a document they can edit) without being admins. Stem's position is no, for the reason above, and that admins of subtrees are cheap.

    Open: the bound on group nesting depth, and whether a group may be owned by another group.

    Open: whether expires should also be allowed on Node blobs (time-limited publications) or stay a grant-only field.

See also

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime