Re: Restarting work on the zCap (Authorization Capabilities) work item

Dmitri,
I am pleased to see renewed interest in updating zCap. Over the years, I've
suggested several times that zCap should leverage the work done in the ODRL
community group <https://www.w3.org/community/odrl/>. I hope I'll have
another opportunity to do so. While I recognize that many will suggest a
"full-blown" ODRL implementation is too much to require in a standard
intended for cases where expressiveness of caveats is not required, I
suggest that a minimal profile ODRL can be easily defined to match the
semantics afforded by the current zCap caveat definition. Implementers
should then be free to define their own, potentially more expansive
profiles, as their use case or application requires. This allows zCap to
address a wide variety of requirements and avoids the current need to
define something outside of zCap when a rich rights expression language
like ODRL is necessary.

Below I provide an example, based on old notes, illustrating the difference
between zCap, as currently defined, and what it could look like and enable
if it adopted at least a minimal profile of the ODRL Rights Expression
Language.
zcap examples: current spec vs. minimal ODRL caveat profile

The scenario throughout: Acme Corp’s document management system. The legal
department owns a document collection. The IT department manages the
server. A senior lawyer delegates review authority to junior lawyers, who
may further delegate to paralegals.

This scenario is chosen because the implicit delegation structure is
immediately visible: IT manages the server on behalf of Legal, which itself
operates within constraints set by Acme’s board.
------------------------------
Example 1: Root zcap — current spec

The root zcap identifies the senior lawyer as the controller of the legal
documents collection. The current spec requires that a root zcap have ONLY
four fields. No caveats are permitted.

 <#cb1-1>{ <#cb1-2>  "@context": ["https://w3id.org/zcap/v1"],
<#cb1-3>  "id":
"urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb1-4>
"controller": "did:key:z6MkSeniorLawyer", <#cb1-5>
"invocationTarget": "https://docs.acme.example/legal" <#cb1-6>}

*The invisible problem.* The board granted the legal department authority
over legal documents subject to constraints: client documents may never be
shared outside the firm, and billing records require CFO co-approval for
access. These constraints exist in Acme’s policy documents but are
invisible in the root zcap. Nothing in the zcap chain prevents a delegated
zcap from granting an external party access to client documents — the
monotonicity invariant has nothing to enforce against, because the root
asserts unconstrained authority.
------------------------------
Example 1 (revised): Root zcap — with ODRL minimal profile

The root zcap now makes the board’s constraints explicit. The implicit
delegation — from Acme’s board to the legal department, subject to
confidentiality rules — is now visible in the root.

 <#cb2-1>{ <#cb2-2>  "@context": [ <#cb2-3>
"https://w3id.org/zcap/v1", <#cb2-4>
"https://www.w3.org/ns/odrl/2/" <#cb2-5>  ], <#cb2-6>  "id":
"urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb2-7>
"controller": "did:key:z6MkSeniorLawyer", <#cb2-8>
"invocationTarget": "https://docs.acme.example/legal", <#cb2-9>
"caveat": [{ <#cb2-10>    "type": "odrl:Permission", <#cb2-11>
"odrl:action": ["odrl:read", "odrl:write", "odrl:delete"], <#cb2-12>
 "odrl:constraint": [{ <#cb2-13>      "odrl:leftOperand":
"odrl:recipient", <#cb2-14>      "odrl:operator": "odrl:isPartOf",
<#cb2-15>      "odrl:rightOperand": { <#cb2-16>        "@value":
"https://directory.acme.example/employees" <#cb2-17>      } <#cb2-18>
  }] <#cb2-19>  }] <#cb2-20>}

Now any delegated zcap that attempts to grant access to a party outside
Acme’s employee directory is a detectable monotonicity violation. The
constraint that was invisible is now enforceable.
------------------------------
Example 2: First delegation — current spec (URL-path attenuation)

The senior lawyer delegates read authority to a junior lawyer, restricted
to the contracts subdirectory. Attenuation is expressed only by narrowing
the invocationTarget URL.

 <#cb3-1>{ <#cb3-2>  "@context": ["https://w3id.org/zcap/v1"],
<#cb3-3>  "id": "urn:uuid:b1c2d3e4-0001", <#cb3-4>
"parentCapability": <#cb3-5>
"urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb3-6>
"controller": "did:key:z6MkJuniorLawyer", <#cb3-7>
"invocationTarget": "https://docs.acme.example/legal/contracts",
<#cb3-8>  "allowedAction": ["read"], <#cb3-9>  "expires":
"2026-12-31T00:00:00Z", <#cb3-10>  "proof": { <#cb3-11>    "type":
"Ed25519Signature2020", <#cb3-12>    "proofPurpose":
"capabilityDelegation", <#cb3-13>    "capabilityChain": [ <#cb3-14>
  "urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal" <#cb3-15>
], <#cb3-16>    "verificationMethod":
"did:key:z6MkSeniorLawyer#key-1", <#cb3-17>    "proofValue": "z..."
<#cb3-18>  } <#cb3-19>}

The restriction to the contracts subdirectory is implicit in the URL. The
allowedAction restricts to read. Nothing else is expressible — the junior
lawyer could be granted access to contracts from any client, active or
closed, with no way to constrain further without restructuring the URL
hierarchy.
------------------------------
Example 2 (revised): First delegation — ODRL minimal profile

The same delegation, but with an explicit ODRL constraint making the
attenuation readable and extensible. The minimal profile uses only
odrl:isPartOf — semantically identical to the URL prefix check, now
expressed in standard vocabulary.

 <#cb4-1>{ <#cb4-2>  "@context": [ <#cb4-3>
"https://w3id.org/zcap/v1", <#cb4-4>
"https://www.w3.org/ns/odrl/2/" <#cb4-5>  ], <#cb4-6>  "id":
"urn:uuid:b1c2d3e4-0001", <#cb4-7>  "parentCapability": <#cb4-8>
"urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb4-9>
"controller": "did:key:z6MkJuniorLawyer", <#cb4-10>
"invocationTarget": "https://docs.acme.example/legal/contracts",
<#cb4-11>  "allowedAction": ["read"], <#cb4-12>  "expires":
"2026-12-31T00:00:00Z", <#cb4-13>  "caveat": [{ <#cb4-14>    "type":
"odrl:Permission", <#cb4-15>    "odrl:action": ["odrl:read"],
<#cb4-16>    "odrl:constraint": [{ <#cb4-17>      "odrl:leftOperand":
"odrl:target", <#cb4-18>      "odrl:operator": "odrl:isPartOf",
<#cb4-19>      "odrl:rightOperand": { <#cb4-20>        "@value":
"https://docs.acme.example/legal/contracts" <#cb4-21>      } <#cb4-22>
   }] <#cb4-23>  }], <#cb4-24>  "proof": { <#cb4-25>    "type":
"Ed25519Signature2020", <#cb4-26>    "proofPurpose":
"capabilityDelegation", <#cb4-27>    "capabilityChain": [ <#cb4-28>
  "urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal" <#cb4-29>
], <#cb4-30>    "verificationMethod":
"did:key:z6MkSeniorLawyer#key-1", <#cb4-31>    "proofValue": "z..."
<#cb4-32>  } <#cb4-33>}

A verifier implementing only the minimal profile evaluates this exactly as
it evaluated the URL prefix before. Semantically identical; now explicit
and standard.
------------------------------
Example 3: Second delegation — current spec

The junior lawyer delegates to a paralegal, restricted to a single client’s
contracts folder.

 <#cb5-1>{ <#cb5-2>  "@context": ["https://w3id.org/zcap/v1"],
<#cb5-3>  "id": "urn:uuid:b1c2d3e4-0002", <#cb5-4>
"parentCapability": "urn:uuid:b1c2d3e4-0001", <#cb5-5>  "controller":
"did:key:z6MkParalegal", <#cb5-6>  "invocationTarget": <#cb5-7>
"https://docs.acme.example/legal/contracts/client-xyz", <#cb5-8>
"allowedAction": ["read"], <#cb5-9>  "expires":
"2026-06-30T00:00:00Z", <#cb5-10>  "proof": { <#cb5-11>    "type":
"Ed25519Signature2020", <#cb5-12>    "proofPurpose":
"capabilityDelegation", <#cb5-13>    "capabilityChain": [ <#cb5-14>
  "urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb5-15>
   { "id": "urn:uuid:b1c2d3e4-0001", "...": "full zcap embedded" }
<#cb5-16>    ], <#cb5-17>    "verificationMethod":
"did:key:z6MkJuniorLawyer#key-1", <#cb5-18>    "proofValue": "z..."
<#cb5-19>  } <#cb5-20>}

------------------------------
Example 3 (revised): Second delegation — ODRL minimal profile

 <#cb6-1>{ <#cb6-2>  "@context": [ <#cb6-3>
"https://w3id.org/zcap/v1", <#cb6-4>
"https://www.w3.org/ns/odrl/2/" <#cb6-5>  ], <#cb6-6>  "id":
"urn:uuid:b1c2d3e4-0002", <#cb6-7>  "parentCapability":
"urn:uuid:b1c2d3e4-0001", <#cb6-8>  "controller":
"did:key:z6MkParalegal", <#cb6-9>  "invocationTarget": <#cb6-10>
"https://docs.acme.example/legal/contracts/client-xyz", <#cb6-11>
"allowedAction": ["read"], <#cb6-12>  "expires":
"2026-06-30T00:00:00Z", <#cb6-13>  "caveat": [{ <#cb6-14>    "type":
"odrl:Permission", <#cb6-15>    "odrl:action": ["odrl:read"],
<#cb6-16>    "odrl:constraint": [{ <#cb6-17>      "odrl:leftOperand":
"odrl:target", <#cb6-18>      "odrl:operator": "odrl:eq", <#cb6-19>
  "odrl:rightOperand": { <#cb6-20>        "@value": <#cb6-21>
"https://docs.acme.example/legal/contracts/client-xyz" <#cb6-22>
} <#cb6-23>    }] <#cb6-24>  }], <#cb6-25>  "proof": { <#cb6-26>
"type": "Ed25519Signature2020", <#cb6-27>    "proofPurpose":
"capabilityDelegation", <#cb6-28>    "capabilityChain": [ <#cb6-29>
  "urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb6-30>
   { "id": "urn:uuid:b1c2d3e4-0001", "...": "full zcap embedded" }
<#cb6-31>    ], <#cb6-32>    "verificationMethod":
"did:key:z6MkJuniorLawyer#key-1", <#cb6-33>    "proofValue": "z..."
<#cb6-34>  } <#cb6-35>}

The constraint narrows from isPartOf /legal/contracts (parent) to eq
/legal/contracts/client-xyz (this delegation). A verifier checks
monotonicity: the satisfying set of eq client-xyz is a subset of the
satisfying set of isPartOf /legal/contracts. Monotonicity holds. The check
is a simple string containment, identical in cost to the URL prefix check.
------------------------------
Example 4: What ODRL enables beyond URL-path attenuation

*Scenario:* The senior lawyer wants to grant a paralegal read access to
contracts for active clients only (not closed matters), during business
hours only, and no more than 20 documents per day. None of this is
expressible with URL path attenuation — the document’s status, the time of
day, and the access count are not properties of the URL.

*Current spec:* Inexpressible. Three workarounds, all bad: (a) build
status, time, and count into the URL hierarchy and restructure the entire
API; (b) implement these constraints in application logic outside the zcap
chain, where they are invisible to delegatees and unauditable; (c) issue
separate zcaps for each case and manage their lifecycle manually.

*With an extended ODRL profile:*

 <#cb7-1>{ <#cb7-2>  "@context": [ <#cb7-3>
"https://w3id.org/zcap/v1", <#cb7-4>
"https://www.w3.org/ns/odrl/2/" <#cb7-5>  ], <#cb7-6>  "id":
"urn:uuid:b1c2d3e4-0003", <#cb7-7>  "parentCapability": <#cb7-8>
"urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal", <#cb7-9>
"controller": "did:key:z6MkParalegal", <#cb7-10>  "invocationTarget":
"https://docs.acme.example/legal/contracts", <#cb7-11>
"allowedAction": ["read"], <#cb7-12>  "expires":
"2026-12-31T00:00:00Z", <#cb7-13>  "caveat": [{ <#cb7-14>    "type":
"odrl:Permission", <#cb7-15>    "odrl:action": ["odrl:read"],
<#cb7-16>    "odrl:constraint": [{ <#cb7-17>      "odrl:and": [
<#cb7-18>        { <#cb7-19>          "odrl:leftOperand":
"odrl:target", <#cb7-20>          "odrl:operator": "odrl:isPartOf",
<#cb7-21>          "odrl:rightOperand": { <#cb7-22>
"@value": <#cb7-23>
"https://docs.acme.example/legal/contracts" <#cb7-24>          }
<#cb7-25>        }, <#cb7-26>        { <#cb7-27>
"odrl:leftOperand": "odrl:status", <#cb7-28>          "odrl:operator":
"odrl:eq", <#cb7-29>          "odrl:rightOperand": {"@value":
"active"} <#cb7-30>        }, <#cb7-31>        { <#cb7-32>
"odrl:leftOperand": "odrl:timeInterval", <#cb7-33>
"odrl:operator": "odrl:isPartOf", <#cb7-34>
"odrl:rightOperand": {"@value": "09:00/17:00"} <#cb7-35>        },
<#cb7-36>        { <#cb7-37>          "odrl:leftOperand":
"odrl:count", <#cb7-38>          "odrl:operator": "odrl:lteq",
<#cb7-39>          "odrl:rightOperand": <#cb7-40>
{"@value": "20", "@type": "xsd:integer"}, <#cb7-41>
"odrl:unitOfCount": "odrl:perDay" <#cb7-42>        } <#cb7-43>      ]
<#cb7-44>    }] <#cb7-45>  }], <#cb7-46>  "proof": { <#cb7-47>
"type": "Ed25519Signature2020", <#cb7-48>    "proofPurpose":
"capabilityDelegation", <#cb7-49>    "capabilityChain": [ <#cb7-50>
  "urn:zcap:root:https%3A%2F%2Fdocs.acme.example%2Flegal" <#cb7-51>
], <#cb7-52>    "verificationMethod":
"did:key:z6MkSeniorLawyer#key-1", <#cb7-53>    "proofValue": "z..."
<#cb7-54>  } <#cb7-55>}

All four constraints are evaluated locally by the document management
server. No network calls. The evaluation is bounded and decidable. The
paralegal who receives this zcap can read the caveat and understand exactly
what authority they hold — which is itself a security property: authority
is legible, not hidden in server-side policy logic.
------------------------------
Summary
Current spec Minimal ODRL profile Extended ODRL profile
Root caveats Not permitted Permitted Permitted
Implicit delegation visible No Yes Yes
Attenuation vocabulary URL prefix (implicit) odrl:isPartOf (explicit) Full
ODRL constraint set
Monotonicity enforcement URL string containment Constraint set
containment Constraint
set containment
Backward compatible — Yes Opt-in per verifier
Verifier complexity String prefix check Same + ODRL parser ODRL constraint
evaluator
Legibility for delegatee Poor Good Good

The minimal ODRL profile is a direct, backward-compatible replacement for
URL-path attenuation, with no additional security risk and improved
legibility. The extended profile enables use cases that are currently
inexpressible. Both require only that the root zcap’s MUST NOT restriction
be relaxed to permit caveat fields.

On Wed, Apr 1, 2026 at 8:06 PM Dmitri Zagidulin <dzagidulin@gmail.com>
wrote:

> Hi all,
> A few weeks ago on the CCG call discussing the various work items, I
> brought up the subject of zCaps (Authorization Capabilities), which is an
> existing (if somewhat dormant) CCG work item, at
> https://github.com/w3c-ccg/zcap-spec. And several people have expressed
> interest in working on that spec again.
>
> In parallel, the Delegated Authorization Task Force of the Trusted AI
> Agent WG at DIF has been evaluating various delegated authorization
> specifications (including zCaps, various OAuth-based specs, UCANs, GNAP,
> and many others), and has determined that there's not many authorization
> options out there with chained delegation ability (basically, zCaps
> (JSON-based) and UCANs (DAG-CBOR-based) are the only ones). This is
> especially relevant and timely due to all the momentum and activity behind
> agent-based development, and the lack of authorization and guardrails in
> that area.
>
> To that end, I'd like to restart work on the zCap spec here at the CCG.
> The current spec version is v0.3, but it's been out of sync with the way
> zcaps have been deployed to production by the TruAge project, Digital
> Bazaar, DCC, and others.
> So our first goal would be to just update the spec to v0.4, to match the
> existing implementations.
>
> It would be also great to start work on version v0.5, as several new use
> cases and feature requests have come up in the meantime.
>
> So, couple of questions of the group:
>
> 1. Would anyone like to help edit the spec?
>
> 2. Would folks be interested in a zCap task force call, either monthly or
> bi-weekly, to work on the spec?
>
> Thanks!
>
>
>
>

Received on Thursday, 2 April 2026 14:46:20 UTC