DEOS UCAN-shaped Capability Tokens — v1 Specification

Status: v1.0 — published 2026-05-02 Spec URI: https://projectmaya.deoscomputing.io/ucan/tokens/v1 Maintainer: DEOS Computing (did:web:deos.computing) Reference impl: Rust crate in DEOS Computing's working repo (access-controlled during v1 alpha).

A capability token in v1 is a UCAN-shaped JSON object carried inline on a receipt's capability.chain array. It targets UCAN v1.0 semantics (2024) — iss, aud, att, prf, exp, nbf, nnc — but uses a different encoding (inline canonical JSON instead of JWT base64) so a receipt remains a single canonical-JSON object end to end. See §7 for v0.10.0 ↔ v1.0 alignment.

This document is normative for v1.


1. Token shape

{
  "iss": "did:deos:user-maya",
  "aud": "did:deos:agent-maya-2026",
  "att": [
    {"with": "wallet://maya/usd", "can": "spend", "max": 200000}
  ],
  "exp": 1746201600,
  "nbf": 1746000000,
  "nnc": "vec02-root",
  "prf": ["<hex>", ...],
  "s": {
    "alg": "ed25519",
    "kid": "did:deos:user-maya#sig-1",
    "sig": "<base64url-nopad of 64 bytes>"
  }
}
Field Required Notes
iss yes DID of the issuer (the entity granting/delegating).
aud yes DID of the audience (the entity being granted to).
att yes Non-empty array of attenuations (capabilities granted).
exp yes Expiry, integer unix seconds.
nbf optional Not-before, integer unix seconds.
nnc optional Nonce. RECOMMENDED (replay-resistance).
prf optional Hashes (BLAKE3 hex) of parent tokens, when not embedded inline. v1 chains are inline so prf is informational.
s yes Inline signature object — see §3.

1.1 Attenuation shape

Each entry in att is an object:

{
  "with": "<resource URI>",
  "can": "<verb>",
  "<caveat-name>": <caveat-value>,
  ...
}

Caveat semantics in v1:

A full caveat-evaluator with richer semantics ships in M6.

2. Wire form

Tokens are embedded directly into a receipt's capability.chain array (in order, root-first). They are NOT JWT-encoded.

A v1 chain has at least one token; common shapes:

3. Signature payload

The signature in s covers the full token body with the s field removed, prefixed with a fixed domain-separation tag:

sig_payload = "deos-ucan-v1:" || JCS(token minus { s })
s.sig       = base64url-nopad(Ed25519_sign(secret_key, sig_payload))

Where JCS is the same canonicalization as receipt format v1 §4.1 (RFC 8785-compatible for the integer/string/bool/null/array/object subset).

4. Validity rules (normative)

A capability chain C[0..n] is valid for a receipt R iff all of the following hold:

4.1 Per-token signature

For each C[i]:

  1. C[i].s.alg == "ed25519".
  2. C[i].s.kid MUST start with <C[i].iss>#. (The kid is owned by the token's issuer.)
  3. The verifying key resolved from C[i].s.kid (via DID document, or in reference impl test mode via deterministic derivation — see §6) verifies C[i].s.sig against sig_payload(C[i]).

4.2 Chain continuity

  1. C[0].iss == R.principal. The root issuer is the receipt's principal.
  2. For each 0 < i < n: C[i-1].aud == C[i].iss. Each delegation hands off to the next issuer.
  3. C[n].aud == R.subject. The leaf audience is the agent acting.

4.3 Time bounds

For each C[i], with t = R.issued_at_ns / 1_000_000_000:

  1. t <= C[i].exp (token not expired at receipt-issue time).
  2. If C[i].nbf present: t >= C[i].nbf.

4.4 Attenuation narrowing

For each non-root token C[i] (i > 0):

composed[i] is the list of attenuations from C[i].att that survive narrowing against composed[i-1]. composed[0] == C[0].att.

If any child attenuation cannot be narrowed from at least one parent attenuation, the chain is invalid with an attenuation-mismatch error.

4.5 Action satisfaction

The receipt's action MUST be satisfied by composed[n] (the leaf scope). v1 satisfaction is shape-level except for one specific rule:

Other action types pass satisfaction as long as the leaf scope is non-empty. M6 introduces full caveat evaluation for all action types.

4.6 Revocation

M7 adds a check that no token in the chain appears in the substrate's revocation log. v1 implementations omit this check; the verifier MUST tolerate its absence.

5. Receipt linkage

Receipts produced by a v1 substrate MUST carry a capability.chain with at least one token. The attestation API (/attestation/api/v1) MUST validate the chain (§4) on POST /append and reject receipts whose chain fails validation with HTTP 400.

An external verifier MUST validate the chain (§4) on every GET /receipt/{id} flow before returning VALID. A chain-validation failure SHOULD be reported as INVALID:capability:<reason>.

6. Test-key derivation (REFERENCE IMPL ONLY)

For unit tests and demos, signing keys for test DIDs are derived deterministically:

secret_seed = BLAKE3("deos-test-key-v1:" || did)[..32]
signing_key = Ed25519::from_seed(secret_seed)

This makes the M1 test vectors fully reproducible without committing private keys to the repo. Production substrates MUST NOT use this derivation — production keys come from HSMs and are published via DID documents.

The reference test resolver returns derived keys for any kid of shape <did:deos:*>#sig-1. Production DID resolvers use the underlying DID method (/did/deos/v1).

7. Wire compatibility note (UCAN v1.0)

Updated 2026-05-05 per UCAN1.1-7. This document targets the UCAN v1.0 model (2024) — the WG-stable line that supersedes v0.10.0. Semantic field names match v1.0:

A v1 DEOS token is semantically wire-compatible-via-translation with a UCAN v1.0 token:

The decision to use inline JSON instead of JWT is deliberate:

A future v1.2 MAY add a JWT-import / JWT-export translation layer for interop with non-DEOS UCAN v1.0 ecosystems (tracked as UCAN1.1-1).

v0.10.0 → v1.0 migration deltas (informational)

Implementations that previously targeted UCAN v0.10.0 should note these v1.0 changes:

8. Open questions deferred


9. Maintainer

DEOS Computing — design questions, conformance reports, and proposed additions to github.com/DEOS-Computing.

License: CC BY 4.0 (text), Apache-2.0 (reference code).