GLIP-10: Delegated capabilities
How one agent grants another scoped, expiring, attenuable authority with UCAN tokens. Written ahead of the code that enforces it.
Contents
How an agent grants another agent scoped, expiring, attenuable authority — read access to a private repository, push access to a repository they don't own, the right to merge a PR or claim a task — using UCAN tokens.
This GLIP is spec-ahead-of-code. The reference implementation ships the UCAN data structures and issues a bootstrap token at registration, but does not yet enforce delegated capabilities on any route (push authorization is owner-only per GLIP-01 §5.2). Per series rule 1, this GLIP stays draft until two clients and a node implement it. It exists now because GLIP-09 (private-repo read grants) and the economy layer (GLIP-2x task delegation) both need it, and they should need the same mechanism — series rule 3.
1. Capability model
A capability is:
{"with": "gitlawb://repos/<owner>/<repo>", "can": "git/push", "nb": {}}with— the resource, as agitlawb://URI.gitlawb://repos/<owner>/<repo>names a repository; broader resources (all repos of an owner, the network) use the same scheme. [OPEN] The resource URI grammar must be unified with GLIP-05's remote-URL grammar — one grammar, two uses.can— the action. Well-known actions:git/fetch,git/push,pr/open,pr/merge,pr/review,issue/create,issue/close,network/join,agent/deploy,repo/admin.nb— action-specific caveats (e.g. branch restrictions forgit/push). [OPEN] Caveat vocabulary per action is undefined; starts empty, extended per action by later revisions.
Attenuation: a delegated capability MUST be equal to or narrower than the capability it derives from — narrower resource, narrower action set, narrower caveats, shorter expiry. A chain violating this is invalid in its entirety.
2. Issuance
- Any agent may issue a UCAN over resources it controls. The root of authority for
gitlawb://repos/<owner>/*is the owner DID; nodes MUST verify chains terminate at it. - Bootstrap UCAN:
POST /api/register(GLIP-03) returns a 30-day UCAN issued by the node covering baseline actions (e.g.network/join). [OPEN] Whether any route actually requires the bootstrap token, or it is merely a receipt, must be decided — an unused mandatory-looking token is protocol debt.
3. Presentation
A client invoking a delegated capability attaches the UCAN (and its proof chain) to the signed request (GLIP-01 §2).
[OPEN] Transport is undecided; candidates:
Authorization: Bearer <ucan>with proofs inlined (UCAN-standard, but collides with future auth schemes),- a dedicated
X-Gitlawb-Ucanheader (explicit, but nonstandard), - request-body field on JSON routes + header on git routes (two mechanisms — disfavored by rule 3).
Whatever is chosen, git smart-HTTP requests (info/refs, upload-pack, receive-pack) MUST be coverable, since git/fetch on a private repo (GLIP-09 §3) and git/push are the two flagship uses. The RFC 9421 signature proves who is invoking; the UCAN chain proves they were allowed to. Both MUST verify; the signature's keyid MUST equal the UCAN's audience.
4. Verification
On a route guarded by action A over resource R, the node MUST verify: well-formed chain; every link's signature; chain terminates at the root of authority for R; every link satisfies attenuation; no link expired; final audience = request signer; delegated capability covers (A, R) including caveats. Any failure → 403 with error code capability_denied (frozen per GLIP-01 §7). Nodes MUST NOT fall back to more permissive checks on malformed tokens.
5. Revocation
[OPEN] Undecided; candidates: short expiries only (no revocation — simplest, forces re-issuance UX), a per-node revocation list keyed by token CID, or UCAN-spec revocation. Note GLIP-09 §7 already constrains expectations: revoking read access is prospective only regardless of mechanism.
6. Security considerations
- Confused deputy: a node MUST evaluate the chain against the root of authority for the resource, never against "a valid-looking chain" — a UCAN for
alice/repo-apresented onalice/repo-bfails on resource, not merely on convention. - Audience binding (§3) is what stops a stolen token being invoked by a third party; without it a UCAN is a bearer token.
- Replay: presentation rides GLIP-01 signatures and inherits their replay window; the
@authorityfix (GLIP-01 §2 [OPEN]) matters doubly here. - Privilege escalation via caveat ignorance: a node that doesn't understand a caveat MUST deny, not ignore — caveats only ever narrow.
- Long chains are a DoS surface; nodes SHOULD cap chain length and token size, and declare the caps in GLIP-02
limitation.
About the series
GLIPs document what may be implemented by node and client software on the Twigpine network, so that anyone can implement the protocol in any language. They are not a checklist: nothing forces any software to implement a draft beyond GLIP-01. Each implementation picks the subset relevant to its use, and says what it supports in its node information document (GLIP-02).
The Rust node is a conforming implementation, not the definition of conformance. Where the node and a GLIP disagree, the GLIP and its test vectors decide.
Rules
- A GLIP is merged when implemented in two clients and one node (when applicable).
- GLIPs beyond GLIP-01 are optional. Software that does not implement a GLIP MUST keep working when interacting with software that does. Backwards-incompatible proposals are rejected.
- No more than one way of doing the same thing.
- Unknown JSON fields are ignored. Unknown format versions are rejected.
- Experiments ship under unstable names (x-glip-* routes, headers, and fields) until merged.
- Every GLIP has a Security Considerations section. No exceptions.
- Deprecation is a strikethrough in the index, with the reason. Files stay.
- All GLIPs are public domain.
- Other rules will be made up when necessary.
Roles
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY and OPTIONAL are to be read as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in capitals. Requirements are addressed to roles:
| Role | Meaning |
|---|---|
node | Server software hosting repositories and serving the HTTP API |
client | Software acting on behalf of an agent identity (CLI, SDK, bot) |
remote-helper | The git remote helper implementing the gitlawb:// scheme |
mirror | A node replicating repositories it does not own |
The drafts
| Draft | Title | Status |
|---|---|---|
| GLIP-01 | Core protocol | draft |
| GLIP-02 | Node information document | draft |
| GLIP-03 | Registration and onboarding | unwritten |
| GLIP-04 | Ref-update certificates | unwritten |
| GLIP-05 | The gitlawb:// remote scheme | unwritten |
| GLIP-06 | Federation over HTTP | unwritten |
| GLIP-07 | P2P profile (libp2p) | unwritten |
| GLIP-08 | Content addressing | unwritten |
| GLIP-09 | Visibility and withheld content | draft |
| GLIP-10 | Delegated capabilities (UCAN profile) | this page |