Capabilities
A capability authorizes one principal to perform a specific ability against a specific resource, optionally narrowed by caveats. It is the atomic unit of authority in TinyCloud: every read or write is the invocation of a capability that traces, through a delegation chain, back to an space's owner DID. There is no access-control list and no server-side session to consult — the capability is the authorization.
Role
Capabilities are Layer 1 bedrock. They make authority portable and verifiable without a server: a holder presents a capability chain and a node admits the request by checking signatures and scope alone (see thesis). The same triple is what the policy engine emits (as a portable-delegation) and what an invocation exercises — so capabilities are the lingua franca that ties L1 authorization to L2/L3 apps.
Shape
A capability is the triple resource × ability × caveats:
- resource —
{spaceId}/{service}[/{path}], the thing acted on, e.g.tinycloud:pkh:eip155:1:0xf39f…2266:default/kv/notes/. Full grammar in uri-addressing-grammar. - ability —
{namespace}.{service}/{action}, the verb, e.g.tinycloud.kv/put,tinycloud.sql/query,tinycloud.space/host. The service set is enumerated in services. - caveats — narrowing conditions on the grant: time bounds (
nbf/exp), path/prefix restriction, SQL table scope. See attenuation.
In code, a parsed capability is the Capability struct produced by tinycloud-core/src/util.rs, which normalizes both encodings (below) into { resource, ability, caveats }. The cap-string short form used in grants and the CLI is service:space:path:actions.
Mechanics
Two encodings, one model
Authority enters the system two ways, both reduced to the same Capability:
- Root delegations are SIWE messages carrying a ReCap, serialized as a CACAO — signed directly by the owner DID (an Ethereum key). This is how a wallet grants authority with one signature.
- Sub-delegations and invocations are UCAN tokens signed by session keys.
tinycloud-auth/src/authorization.rsmodelsTinyCloudDelegationas either a UCAN or a SIWE/CACAO, andTinyCloudInvocationas a UCAN.
Verification
A node admits an invocation only if every link of its delegation chain holds (tinycloud-core/src/models/delegation.rs and models/invocation.rs):
- Signature — each delegation/invocation is signed by the principal that the parent delegated to.
- Time — each link's
[nbf, exp]window is contained within its parent's. - Scope — the resource is
extends-covered by the parent (the path-containment rule defined in uri-addressing-grammar) and the ability is covered by the parent's ability. This is attenuation: a child can only narrow, never widen. - Root authority — the chain's root delegation is signed by the DID that owns the target space (
is_root_authoritycompares the space'sbase_didto the root delegator).
The HTTP entry point that runs this is AuthHeaderGetter in tinycloud-node-server/src/auth_guards.rs, which extracts the capability headers off a request before the route executes.
Relationships
Granted via delegation; exercised via invocation; narrowed by attenuation; ended by revocation; rooted at an space's owner; encoded as UCAN or SIWE/CACAO (ReCap); its resource half obeys the uri-addressing-grammar and its ability half names a service; issued in bulk by the policy engine as portable-delegations.
Example
An owner delegates to a session key a single capability: ability tinycloud.kv/get over resource tinycloud:pkh:eip155:1:0xf39f…2266:applications/kv/com.listen.app/transcript/ with a 24-hour exp caveat. An agent holding the resulting UCAN can then tinycloud.kv/get any key under that transcript/ prefix for a day — and nothing else, because extends rejects any resource outside the prefix and attenuation forbids widening the ability. (See example-listen.)
Status & drift
Shipped. The whitepaper writes the ability loosely as prose; the code form is exactly {namespace}.{service}/{action} (e.g. tinycloud.kv/put) — code is canonical (see contradictions). Note the verification path's replay protection rests on time-bounds + the delegation chain; the general invocation path has no dedicated nonce-dedup table (tracked separately, not a docs concern here).
Sources
tinycloud-node:tinycloud-auth/src/authorization.rs(TinyCloudDelegation/TinyCloudInvocation),tinycloud-core/src/util.rs(Capabilityextraction),tinycloud-core/src/models/delegation.rs+models/invocation.rs(verification),tinycloud-node-server/src/auth_guards.rs(AuthHeaderGetter)