Appearance
Capability tokens
A capability token in Matrix is an unforgeable reference to a right. The interface is ICapabilityToken in projects/matrix-3/packages/core/src/core/security/ICapabilityToken.ts. The model follows Mark Miller's capability rules: holding a capability = having the right; capabilities can be attenuated but never amplified; delegation creates chains.
The shape (verbatim)
typescript
// projects/matrix-3/packages/core/src/core/security/ICapabilityToken.ts:40
export interface ICapabilityToken {
/** Unique token ID (e.g., 'cap-1702500000000-abc123') */
id: string;
/** Who minted this capability (realm mount path) */
issuer: string;
/** What this capability grants access to (mount path or pattern) */
subject: string;
/** Rights granted - typed for safety, extensible for custom namespaces */
rights: CapabilityRight[];
/** Additional restrictions (e.g., { maxCalls: 100, expiresAfterUse: true }) */
caveats: Record<string, unknown>;
/** Timestamp when issued (ms since epoch) */
issuedAt: number;
/** Timestamp when expires (ms since epoch) */
expiresAt: number;
/** Parent token ID if delegated (for chain verification) */
parent?: string;
/** Cryptographic signature (Phase 2+ - not implemented in Phase 1) */
signature?: string;
}Rights
The rights catalog (verbatim from ICapabilityToken.ts:23):
typescript
/** Well-known capability rights (compile-time checked) */
export type WellKnownRight = 'read' | 'write' | 'spawn' | 'delegate' | 'invoke' | 'emit';
/** Custom namespace-prefixed rights (extensible) */
export type CustomRight = `${string}:${string}`;| Right | What it allows |
|---|---|
read | read state / receive events from the subject |
write | mutate state / publish to the subject |
spawn | create child actors under the subject |
delegate | mint sub-capabilities derived from this one |
invoke | call ops via request/reply |
emit | publish events |
<ns>:<verb> | custom namespaced right (e.g., acme:approve-invoice) |
The well-known rights are compile-time checked. Custom rights use the namespace:verb shape — "'wirte' fails. 'acme:approve' passes."
Caveats
The free-form caveats map carries restrictions:
| Caveat | Meaning |
|---|---|
maxCalls: number | usable only N times before expiring |
expiresAfterUse: true | one-shot |
boundToCorrelation: <cid> | usable only for one specific correlation id |
boundToSession: <sessionId> | usable only within one session |
<actor-defined>: <value> | actor-specific restriction |
The actor enforcing the capability checks both the rights and the caveats. The framework does not enforce caveats automatically.
Delegation chains
A capability can be delegated by minting a child token whose parent: <id> points to the original. Chain rules:
- The child's rights are a subset of the parent's (attenuation, never amplification).
- The child's caveats are at least as restrictive as the parent's.
- The child's
expiresAtis at most the parent'sexpiresAt. - The chain is verified at use time by walking
parentlinks.
Status: target state, partial. Phase 1 does not yet implement cryptographic signatures (
signaturefield). The token is currently trusted by reference (the issuer's actor identity is enough). Phase 2 introduces signing for cross-process delegation.
How tokens are used today
The MatrixActor base class accepts a _factCapability: ICapabilityToken | null field used by the blackboard layer (MatrixActor.ts:413). Most ops do not use capability tokens directly; authorization today is per-actor and per-op (the actor decides whether to honor the request based on the caller's principal).
Where tokens DO appear:
- Fact-plane emit on the blackboard requires a
_factCapability. - Cross-actor delegation through
system.security(target). - Marketplace-paid blackboard reads (target —
payment.requiredemits).
For most actor code, the relevant security model is:
- The transport metadata identifies the principal (no payload trust).
- The actor decides per-op whether to honor.
- Cross-tenant requests are blocked by NATS account ACL on the wire, not by tokens.
Capability tokens are the layer above this for fine-grained delegation and attenuation.
Why capability semantics
The Miller model is the canonical pattern for delegation in actor systems (see Mark Miller's Robust Composition). Three properties Matrix relies on:
- Designation = authorization. If you have the token, you have the right. There is no separate ACL table to consult.
- Confused-deputy resistance. A capability cannot be tricked into acting beyond what it grants. Unlike an ambient-auth ACL check, the actor doesn't need to know who is asking — only what the token allows.
- Composable least privilege. Delegating a sub-capability with attenuated rights is the natural way to give code "just enough" auth.
Anti-patterns
- Don't put a capability in a payload. The transport-metadata principal is what authorizes. Tokens travel as actor-state references (
_factCapability), not as untrusted JSON fields. - Don't treat
idas authoritative. The full token (including rights, caveats, expiry, parent) must be verified. Just the id is not enough. - Don't skip expiry. A token without an expiry check is effectively bearer-permanent.
- Don't sign-then-trust without checking the chain. Even with signatures (target state), the
parentchain must be walked.
See also
- Topic claims — wire-level publish/subscribe gate.
- Principal identity — who the caller is.
- Credentials references — credentials are not capabilities.