Repository navigation
Make the right to delegate a capability a capability of its own #323
Description
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-isand 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
parentfield repurposed from "the token narrowed" to "the authorisation for this mint", or a separate field. - Whether
delegations-remainingstays as a hard depth cap alongside the grant-capability. - Whether recipient restrictions ("only to these principals") belong in
conditionsrather than new fields. - Registry entry in
spec/registry/core-capabilities.md, verifier changes inverifyTokenChainandcanGrant, and golden vectors inconformance/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
Mearman commentedon Oct 1, 2026
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
conditionsdeliberately has no such inheritance. The counter, narrowing,conditionsand 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:revokeis 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.Mearman commentedon Oct 1, 2026
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.