Skip to content

Make the right to delegate a capability a capability of its own #323

Closed

Description

@Mearman

Make the right to delegate a capability a capability of its own

Delegating a capability today is governed by the delegations-remaining counter on the token itself. Whoever holds a room:member token can use it and, while the counter allows, mint child tokens from it; there is no way to give someone the right to hand a capability out without also giving them the capability. A room admin who can invite people but cannot read or post in the room is not expressible.

Design direction: grantability is itself a permission. Whether an actor may grant a capability over a scope is carried by a token like any other permission, and the resource's owner is the chain root, which is what ends the delegation regress: every grant below the owner needs a grant-capability from above, each hop only narrows, and the chain terminates at the owner. room.cddl already states that root rule for rooms; it needs stating for every scope kind.

Like every other permission, the grant permission must be conditional: trilean conditions (or similar) on the grant-capability, so an issuer can constrain what its holder may do with it. The named case: a grant permission can be barred from being granted to its own holder, so a holder cannot perpetuate its grant authority. The same conditionality covers delegate-without-use, since an issuer can equally bar the holder from granting the underlying capability to itself (the self-grant case: a delegation's bearer is otherwise unconstrained, so a delegator can name itself).

Questions to settle:

  • How a grant-capability's conditions bind the grants it authorises. Conditions today are evaluated against the token that carries them and deliberately do not inherit, so the verifier evaluating a minted grant must instead evaluate the authorising grant-capability's conditions against the minted child's own claims (bearer-is and its negation are already registered resolvers), fail-closed as today. Mint-time enforcement stays a convenience check only; a hostile holder can hand-craft the COSE, so verify-time is where it must hold.
  • How a minted grant references the grant-capability that authorised it: the existing parent field repurposed from "the token narrowed" to "the authorisation for this mint", or a separate field.
  • Whether delegations-remaining stays as a hard depth cap alongside the grant-capability.
  • Whether recipient restrictions ("only to these principals") belong in conditions rather than new fields.
  • Registry entry in spec/registry/core-capabilities.md, verifier changes in verifyTokenChain and canGrant, and golden vectors in conformance/ so the Rust and TypeScript implementations agree.

Related: #237 (principal-scoped dm:send and its sub-delegation), #84 (delegating revoke authority), #324 (the request counterpart under the same model).

Activity

  1. added theissue type on Oct 1, 2026
  2. Mearman commented on Oct 1, 2026

    @Mearman
    MemberAuthor

    Closing without implementing. The case that would make this orthogonal is a delegator who may hand a capability out but may not use it, and the model cannot express that separation. A delegation's bearer is unconstrained, so whoever may mint a child of a token may mint one naming themselves; the new tests in #325 pin that in both implementations. The right to delegate therefore already includes the right to use. Closing the gap would need tokens to restrict who their children may name as bearer, which means inheriting restrictions through a chain, and conditions deliberately has no such inheritance. The counter, narrowing, conditions and short expiries already bound what a delegate can hand out, and an owner who does not want a holder to use a capability gives it no token and mints root-level grants itself. manage:revoke is a separate capability because revoking confers nothing the revoker could grant itself, which is not true of delegating. The reasoning is recorded in spec/tokens.cddl.

  3. reopened this on Oct 1, 2026
  4. Mearman commented on Oct 1, 2026

    @Mearman
    MemberAuthor

    Implemented and merged in #327: manage:grant, the authorised-by link with its verifier obligations, subject-mode conditions with the grantee-is/granted-capability-is systems (so an issuer can bar the holder from granting the permission or the underlying capability to itself), the chain-root rule stated for every scope kind, both implementations, and conformance vectors. #324 landed the request counterpart in #328.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions