| Internet-Draft | HDP Agentic Delegation | October 2026 |
| Dalugoda | Expires 9 April 2027 | [Page] |
Agentic AI systems operate on behalf of human principals, often delegating tasks through multi-step chains of AI agents. There is currently no standard mechanism to record who authorized an agent to act, under what scope, and through what chain of delegation, in a way that can be verified offline, without a central registry, and without third-party trust anchors.¶
This document specifies the Human Delegation Provenance Protocol (HDP) version 0.1, a lightweight token-based protocol that captures, structures, cryptographically signs, and verifies human delegation context in agentic AI systems. An HDP token binds a human authorization event to a session, records each agent's delegation action as a signed hop in an append-only chain, and lets an auditor verify the integrity of the full record using only the issuer's Ed25519 public key. Verification is fully offline. No registry lookup, no network call, and no third-party trust anchor is required.¶
HDP's distinguishing contribution is a signed, tamper-evident record of what the human asked for and of how each agent read and acted on that request. On deployments that use capability-based delegation formats such as UCAN and ZCAP-LD, the same content can travel in the capability certificates' own metadata instead of a separate token. The underlying append-only, offline-verifiable chain-of-custody mechanism is payload-agnostic; human-authorized agentic delegation is the reference profile specified in this document.¶
HDP is not an authorization protocol. An HDP token confers no authority and is not an input to any access decision. It is a record of who authorized a task and of what each agent declared it did with that authorization, carried with the task and read at audit.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 9 April 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Autonomous AI agents are increasingly used to execute consequential actions: sending emails, modifying files, running code, calling APIs, and transacting on behalf of users. When a human authorizes an orchestrator agent, which in turn delegates to sub-agents, which further delegate to tool-execution agents, the originating human authorization becomes disconnected from the terminal action. There is no standard record of the authorization chain.¶
This gap creates accountability and auditability problems:¶
Recording the human's statement of intent beside each agent's reading of it is one approach to drift, and not a complete one: the record is only as good as the summaries it holds (Section 3.4).¶
HDP addresses this by defining a token that:¶
HDP is not an authorization protocol, and an HDP token is not a capability, an access token, or a credential that entitles its holder to anything. Presenting a valid HDP token to a service does not authorize the presenter to perform the requested action. That decision belongs to the service's own access control mechanism, whether that is OAuth 2.0 (Section 13.2), a capability system such as UCAN or ZCAP-LD (Section 13.4, Section 13.5), or something else. HDP is designed to travel alongside such mechanisms, not to replace them, and not to be an input to them.¶
An HDP token MUST NOT be used as an input to any access decision. A service MUST NOT grant, refuse, or condition an action on the presence of an HDP token, on the outcome of verifying one, or on its contents. A missing token, or one that fails verification, is an audit finding and is recorded as one; it is not a reason to deny a request. A check that can deny is an access control mechanism whatever it is called, and running a second one beside the system's own is a well-known hazard: it adds an independent way to attack the system, and its denials can look to the base mechanism like failures that mechanism was not designed to handle.¶
Several parts of this document can be misread as
authorization if this distinction is not kept in view. The
scope object (Section 3.3) records what
the human declared, in fields named
authorized_tools and authorized_resources
among others; it is a signed record of the authorization
event, not a grant. Integrity verification
(Section 5) establishes that a record is
authentic and intact, not that anyone may act. The HTTP
transport (Section 8) shows a token
accompanying a request because the task travels in the
request and the receiving side records it, not because the
token authorizes it.¶
The reader of an HDP token is whoever examines the record afterwards: post-incident reconstruction of which agent did what, under whose authorization, and in what order; compliance evidence that a human authorized a class of action; and review of how each agent read the human's request. A token is carried with the task and read at audit.¶
Earlier revisions of this document also described a reader
that relied on the token before an action: expiry checks,
session binding, replay defense, and verifier-local revocation
served that reader. This revision removes them. The fields that
supported them, header.expires_at and
header.session_id, remain in the v0.1 wire format and
are described in Section 3.1 as record metadata.
Whether they belong in a future token version is an open
question.¶
The need for agentic delegation provenance is not hypothetical. Production deployments of AI orchestration systems (LangChain, AutoGPT, CrewAI, and similar frameworks) today pass natural language task descriptions between agents with no cryptographic binding to the original human authorization. The operational risk compounds as models become more capable and agents are granted access to higher- consequence tools.¶
A provenance token that travels alongside the task (tamper-evident, offline-verifiable, and scoped to what the human actually approved) provides the foundation for auditable, accountable agentic systems.¶
HDP is designed with the following goals in order of priority:¶
The Intent Provenance Protocol [I-D.haberkamp-ipp] addresses the same problem space. HDP and IPP share the use of Ed25519 signatures and append-only provenance chains but make different architectural trade-offs, which are detailed in Section 13. The two protocols are not interoperable. HDP is offered as a distinct design point, not a revision of IPP.¶
The full HDP protocol specification is available at [HDP-SPEC]. A TypeScript reference implementation is available at [HDP-IMPL]. At the time of writing it implements -02 of this document, including the checks before an action that this revision removes (Section 1.1), and is being updated to match.¶
The core of HDP is an append-only, cryptographically chained record: each hop extends a signed entry that covers all prior state, gaps in the hop sequence are tamper-evident, and any party can verify the entire chain offline using only a public key. This chain-of-custody mechanism is independent of what the chain carries.¶
This document profiles that mechanism for one application:
human-authorized agentic delegation. In this profile the
carried payload is the scope object
(Section 3.3) and each hop record describes an agent
delegation action. The same mechanism could carry other
payloads, for example data provenance, consent delegation, or
physical-world command chains, each as a distinct profile.
Such profiles are out of scope for this document; HDP v0.1
defines only the agentic-delegation profile. Where practical,
the signing (Section 4.1,
Section 4.2) and verification
(Section 5) procedures are described in a
payload-agnostic way so that future profiles can reuse them
unchanged.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] and [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
principal object.¶
chain array.¶
session_id
string, established between the issuer and the agent framework
before the token is issued.¶
An HDP token is a JSON object with six top-level fields. The token MUST conform to the following structure. All integer timestamps are Unix milliseconds (milliseconds since 1970-01-01T00:00:00Z).¶
Before signing or verifying a token, implementations MUST validate its JSON representation and all REQUIRED fields, types, and constraints defined in this section. The input MUST satisfy the I-JSON requirements of RFC 8785, including rejection of duplicate object member names, invalid Unicode strings, and non-finite numbers. Duplicate names MUST be detected before parsing discards them. Values MUST NOT be coerced from strings or booleans to satisfy a numeric field's type.¶
The integer fields header.issued_at,
header.expires_at, and each hop's timestamp
and parent_hop MUST be in the inclusive range 0 through
9007199254740991 (2^53 - 1). Each hop's seq and
scope.max_hops, when present, MUST be in the inclusive
range 1 through 9007199254740991. These are JSON numbers, not
strings. Implementations MUST check their numeric values before
any lossy conversion and MUST reject fractional or out-of-range
values rather than round them. The bounds ensure exact integer
representation in the IEEE 754 double-precision model used by
RFC 8785. They are representation bounds, not a recommended
recording depth. Other numeric values, such as numbers inside
principal.metadata, remain subject to RFC 8785.¶
{
"hdp" : "0.1", // protocol version
"header" : { ... }, // session binding + lifecycle
"principal" : { ... }, // authorizing human
"scope" : { ... }, // declared intent + constraints
"chain" : [ ... ], // delegation hops (append-only)
"signature" : { ... } // root Ed25519 signature
}
The header object carries the record's identifier, its
timing, and the session in which the human authorized the task.¶
{
"token_id" : "550e8400-e29b-41d4-a716-446655440000",
"issued_at" : 1711483200000,
"expires_at" : 1711569600000,
"session_id" : "sess-20260326-abc123",
"version" : "0.1",
"parent_token_id" : "..."
}
¶
issued_at. Records the end of the period for which the
principal authorized the task. It has no effect on integrity
verification (Section 5), and a service
treats a token received after this time no differently from any
other (Section 1.1). A hop whose
timestamp is at or after expires_at is
recorded like any other, and an auditor reports it as recorded
after the authorization period ended
(Section 5.1). HDP defines no default
lifetime.¶
hdp
field.¶
The principal object identifies the authorizing human.
It MUST contain id and id_type. All other
fields are OPTIONAL.¶
{
"id" : "usr_alice_opaque",
"id_type" : "opaque",
"display_name" : "Alice Chen",
"poh_credential" : "...",
"metadata" : {}
}
¶
The id_type field MUST be one of the following defined
values, or a custom string prefixed with x-:¶
opaque: Application-defined identifier. No resolution
semantics are implied.¶
email: An email address as defined in
[RFC5321].¶
uuid: A UUID as defined in [RFC9562].¶
did: W3C Decentralized Identifier
[W3C.DID]. DID resolution is application-
defined and not required by this protocol.¶
poh: A Proof-of-Humanity credential identifier.
Verification semantics are application-defined; see
Section 9.3.¶
HDP does not mandate any specific identity model. The did
id_type is available for deployments with existing DID
infrastructure; it is not required.¶
The scope object records what the human authorized. It
is signed as part of the root signature and MUST NOT be modified
after issuance.¶
The scope object is a record, not a grant. Its fields
describe the authorization the human gave at issuance so that
the record can later be compared with what agents declared
they did. Nothing in this object confers authority on an agent
that holds the token (Section 1.1).¶
{
"intent" : "Analyze Q1 sales data and report.",
"authorized_tools" : ["database_read", "file_write"],
"authorized_resources" : ["db://sales/q1-2026", "file://reports/"],
"data_classification" : "confidential",
"network_egress" : false,
"persistence" : true,
"max_hops" : 3
}
¶
The values above are illustrative. In particular, the
max_hops value shown is an issuer choice for this
example, not a protocol limit.¶
action_summary against, and SHOULD be written to be
both human- and agent-readable. Where practical it SHOULD be
the principal's own words.¶
authorized_tools, this records the declaration and
grants nothing.¶
public, internal,
confidential, restricted. Records the
sensitivity level of data the principal declared the agent
may access.¶
max_hops hops it is not extended (Rule 4 of
Section 4.3). Delegation beyond that depth is
not recorded in this token, and the agent that appended the
final hop is accountable for everything delegated beyond it
(Section 10.5). An issuer MAY choose any
value within the representation bounds in
Section 3, Paragraph 3. If max_hops is
absent, HDP places no limit on the depth recorded.¶
HDP does not mandate a central taxonomy for intent,
authorized_tools, or authorized_resources.
These are self-described by the issuer. Comparing what agents
declared with the declared scope is an audit concern.¶
The authorized_tools and authorized_resources
arrays are independent lists. HDP v0.1 defines no binding
between a tool and the resources it may be used on: the example
above lists two tools and two resources, and nothing in it
states which tool the principal authorized against which
resource. If both resources were databases and one tool wrote
while the other read, the record could not say which tool went
with which database.
Applications MUST NOT infer a per-tool resource binding from a
v0.1 scope. Issuers that need the binding recorded
SHOULD state it in intent, and SHOULD list a resource
for every tool that acts on one, as
Appendix A does.¶
The fixed values are also too coarse. The four
data_classification levels are not the ones every
issuer uses, and a single persistence flag cannot
record that a principal let an agent write log records but
nothing else.¶
The next token version is planned to replace
authorized_tools, authorized_resources,
data_classification, network_egress, and
persistence with one nested structure: a map from each
resource to what the principal declared for it, with values
chosen by the issuer. The map will be required but may be empty,
so that a record declaring nothing can be told apart from one
that says nothing. The following is illustrative only; member
names are not yet fixed:¶
{
"intent" : "Analyze Q1 sales data and report.",
"permissions" : {
"db://sales/q1-2026" : { "actions": ["read"],
"classification": "confidential" },
"file://reports/" : { "actions": ["write"] },
"log://agent-audit" : { "actions": ["append"] }
}
}
¶
These are wire-format changes and are not part of v0.1.¶
The chain array is append-only. Each element records a
single delegation event (hop). The array is empty at issuance and
grows as the token passes through agents. Agents MUST NOT remove
or modify existing entries.¶
{
"seq" : 1,
"agent_id" : "orchestrator-v2",
"agent_type" : "orchestrator",
"agent_fingerprint" : "sha256:abc123...",
"timestamp" : 1711483260000,
"action_summary" : "Decompose task; delegate to sub-agents.",
"parent_hop" : 0,
"hop_signature" : "<base64url-encoded Ed25519 signature>"
}
¶
orchestrator, sub-agent, or
tool-executor. HDP attaches no normative meaning to any
value, and the delegator MAY use any string. Earlier revisions
allowed only four values, the fourth being the literal string
custom; tokens using those values remain valid.¶
timestamp (Rule 5 of
Section 4.3).¶
The action_summary is supplied by whoever submits the
hop, and in v0.1 the issuer signs what it is given
(Section 4.2). When the agent writes its own
summary, the record holds the agent's account of what it did and
is only as reliable as that agent. Where a component outside the
agent's control observes the agent's actions, such as a virtual
machine sidecar, a tool gateway, or an MCP proxy, that component
SHOULD record the hop in place of the agent, and the record
SHOULD identify which component recorded it. HDP v0.1 has no
field for the recording component; until one is added, the
component SHOULD name itself in action_summary.¶
The signature object carries the root signature computed
by the issuer.¶
{
"kid" : "alice-signing-key-v1",
"alg" : "Ed25519",
"value" : "<base64url Ed25519 signature over canonical JSON>"
}
¶
The alg field MUST be Ed25519 for HDP v0.1.
The kid field SHOULD be used by verifiers to identify
the correct public key when multiple keys are in circulation.¶
The root signature is computed by the issuer at token creation time. It covers the token's header, principal, and scope, the fields that constitute the human authorization event.¶
The signing procedure is:¶
hdp, header, principal,
scope, and chain (empty array at issuance)
fields.¶
signature object (kid,
alg, value) to the token.¶
The signature field itself MUST NOT be included in the
canonical JSON payload before signing. Because the root signature
is computed while chain is empty, the signed payload is
deterministically recoverable from a populated token by removing
the signature field, resetting chain to an empty
array, and re-serializing with RFC 8785. The root signature
therefore covers hdp, header, principal,
and scope; the chain is protected by the hop
signatures (Section 4.2) rather than by the root
signature.¶
Each hop MUST carry a hop_signature. This signature
binds the new hop record to the entire accumulated delegation
history and to the root signature, making retroactive chain
modification detectable.¶
The hop signing procedure is:¶
hop_signature).¶
[hop_1, hop_2, ..., hop_(n-1), new_hop_unsigned]
where hop_1 through hop_(n-1) are the
previously signed hops (WITH their hop_signature
fields) and new_hop_unsigned is the new hop record
WITHOUT its hop_signature.¶
[root_sig_value, hop_1, ..., new_hop_unsigned].
This chains the hop signature to the root.¶
hop_signature
field on the new hop record.¶
chain array.¶
The asymmetry between previously-signed hops (WITH
hop_signature) and the new hop (WITHOUT
hop_signature) in step 2 is intentional and critical.
The verifier MUST reconstruct this exact payload structure
when verifying each hop. See Section 5.¶
In HDP v0.1, all signatures (the root signature and every hop signature) are produced by the issuer using a single key. An extending agent that is not the issuer submits its hop to the issuer, which signs it and returns the extended token. Two consequences follow, and implementers should weigh both.¶
First, a v0.1 hop signature attests that the issuer recorded a
delegation claim naming the agent in agent_id. It does
not attest that the named agent consented to, or knew of, the
hop, because the agent signed nothing. The chain is a record of
what the issuer recorded, not of what each agent agreed to.
Deployments in which that distinction matters need per-agent
signing.¶
Second, the single-key design is practical only where the issuer is reachable whenever any agent wishes to extend the chain. This adds a round trip to every delegation, and it makes delegation across trust domains awkward, since an issuer in one domain must sign on behalf of agents in another. Only verification is offline; extension is not.¶
The single-key design does not, however, gain anything for offline verification that per-agent signing would lose. If each hop carried the public key of the agent appending it, signed into the chain by that agent's delegator, a verifier would authenticate every key after the first from the chain itself and would still resolve exactly one key out of band: the issuer's.¶
Issuer signing remains the baseline. Per-agent hop signing on that pattern is planned as an option for a future version, for deployments that can manage agent keys; it is not planned as a replacement. The baseline is kept because it confines signing to one party. OAuth 1.0 [RFC5849] required every client to sign its requests, which developers found hard to get right, and OAuth 2.0 [RFC6749] dropped the requirement and relies on TLS instead. Under the planned option an agent uses a fresh key for each delegation, signed into the chain by its delegator, so an agent key lasts no longer than its task and key rotation comes down to rotating the issuer's key. That design does not yet handle a key compromised during a task, and the extension will have to say how. The option is not part of v0.1, and v0.1 tokens carry no per-agent keys.¶
The following rules govern chain construction and MUST be enforced by both extenders and verifiers:¶
seq values MUST start at 1 and increment by
exactly 1. No gaps are permitted.¶
parent_hop MUST reference a valid prior
hop index (0 for the root human authorization, or the
seq value of a prior hop).¶
scope.max_hops is set, the chain length MUST
NOT exceed it. A token with a full chain MUST NOT be extended;
further delegation is not recorded in it
(Section 10.5).¶
timestamp MUST be greater than or equal
to the timestamp of the hop before it. A chain in which
a hop's timestamp is less than its predecessor's fails
integrity verification (Step 3 of Section 5).
Because the issuer signs every hop in v0.1, all hop timestamps
pass through one clock domain, which is what makes this rule
enforceable.¶
hop_signature field MUST be present on every
hop. A hop without a hop_signature is a protocol
violation and is a verification failure.¶
Integrity verification establishes that a record is as the issuer signed it. A verifier MUST first validate the input as specified in Section 3, then execute the following five steps in order. A failure at any step means that the record's integrity is not established; the verifier MUST report the failure and the step at which it occurred, and MUST NOT proceed to subsequent steps. Integrity verification does not depend on the current time, on a session, or on any state held by the verifier other than the issuer's public key, so a record verifies the same way on the day it is issued and years later.¶
hdp field MUST contain a recognized protocol
version string. For this specification, the only recognized
value is "0.1". The header.version field MUST
equal the hdp field; a mismatch is a failure.¶
signature field and resetting chain to an empty
array (its value when the root signature was computed), then
serializing the remaining token object per RFC 8785. Verify that
signature.alg is Ed25519, then verify the
signature in signature.value against this payload using
the issuer's public key. A failure indicates tampering with the
header, principal, or scope.¶
chain, verify that
hop.seq == (index + 1); any gap or duplication is a
failure. Verify that each hop's parent_hop
references either 0 (the root authorization) or the seq
of a prior hop; an out-of-range parent_hop is a
failure (Rule 3 of Section 4.3). Verify that
each hop's timestamp is greater than or equal to that
of the hop before it; a decrease is a failure (Rule 5 of
Section 4.3).¶
Hop signature verification.
For each hop at index i:¶
hop_signature is present. Absence
is a failure.¶
i without its hop_signature, prepended
by the root signature value.¶
hop_signature against the issuer's public key
(the same key used for the root signature in HDP v0.1).¶
scope.max_hops is defined, the length of
chain MUST NOT exceed it.¶
Verification is fully offline. Steps 1 through 5 require only the issuer's Ed25519 public key. No network call, registry lookup, or third-party contact is required at any step.¶
A record that passes all five steps is authentic and intact: its header, principal, and scope are as the issuer signed them, and every recorded hop is as the issuer recorded it. Passing verification establishes nothing about whether any agent was permitted to act, and failing it is not grounds for refusing an action (Section 1.1).¶
If principal.poh_credential is present, an auditor MAY
check it with an application-defined verifier and report the
result separately from record integrity (Section 9.3).¶
Audit tooling MUST report the following results separately. They are results of examining a record, not new fields in an HDP token:¶
timestamp is at or after
header.expires_at. Such hops are reported as recorded
after the authorization period ended, not discarded. Hop
timestamps are declared values (Section 3.4).¶
header.session_id matches it. A mismatch means the
record belongs to another session; it does not make the record
invalid.¶
parent_token_id, its
relationship to the parent: supersession, joint approval, or
unknown, determined as described in
Section 7.¶
A valid record establishes what the issuer recorded. It does not establish that an action occurred, that the recorded chain is complete (Section 10.4), or that the human authorized a particular action. Applications requiring audit SHOULD retain the tokens, the trusted public keys, and any receipts (Section 10.4) for their audit retention period. Key-compromise information MUST qualify any conclusion drawn from a mathematically valid signature (Section 10.8).¶
HDP v0.1 supports one principal per token. This section covers
recording that more than one human approved the same task, as
under a two-person rule. It is not delegation by several
principals, and no principal's authority is combined with
another's. Human A's approval is recorded in token T1; Human B's
approval is recorded in token T2, with parent_token_id
equal to T1's token_id. Each token is independently
signed with its issuer's key.¶
To examine a joint approval, an auditor MUST:¶
T[i].header.parent_token_id == T[i-1].header.token_id
for all i > 0.¶
session_id.¶
Each principal's approval is a distinct signed artifact, and no threshold signature scheme is needed. A future version of HDP may introduce simultaneous multi-signature primitives using threshold signature schemes.¶
An alternative to chaining is composition: each principal's approval is an independent token, and the application's own records bind the tokens to the task. Chaining is specified here because T2 signs a reference to T1, which puts the link in the record. The link alone does not state that the approvals were for the same action; that meaning requires the application context below. Composition gives equivalent evidence when an authenticated receipt binds both token digests to the task. Without such retained context, neither a bare parent link nor two independent tokens establishes joint approval.¶
The parent_token_id field thus serves two purposes:
supersession, where a new record replaces an earlier one
(Section 6), and joint approval (this
section). HDP v0.1 does not tag which relationship a given
parent_token_id expresses. This is a known weakness: an
audit cannot always determine the relationship from the records
alone. Applications MUST obtain its meaning from trusted, explicit
context, such as an authenticated issuance record identifying the
parent, child, and relationship type. Expiry, principal equality,
and session equality alone MUST NOT be used to infer that
meaning. Applications requiring audit MUST retain this context,
with integrity protection and a binding to each token's issuer
public key and root signature, alongside the tokens. This binding
remains stable as the chains are extended. In its absence,
auditors MUST report the relationship as unknown. The fix is a
signed relationship type in the header, planned for the next
token version. Note also that a superseding token's
session_id MAY differ from that of the token it
supersedes, whereas the tokens in a joint approval MUST share one
session_id.¶
The HTTP header field names defined below do not use the "X-" prefix, in accordance with [RFC6648].¶
HDP tokens MAY be transmitted in HTTP requests and responses
using the HDP-Token header. The header value is the
base64url encoding (RFC 4648, no padding) of the UTF-8
JSON serialization of the complete token object.¶
Implementations MUST NOT include tokens in URL query parameters.
The reason is privacy, not secrecy: a token is not a bearer
secret, but it carries the principal object and the
principal's request, and URLs are written to server logs and
browser histories.¶
A token accompanies a request because the task it records travels in that request, and so that the receiving side, or a recording component in front of it (Section 3.4), can record the next hop and keep the record where an auditor can find it. Its presence does not authorize the request, and the receiving service MUST NOT use it as an input to its decision to act (Section 1.1).¶
HTTP header values are routinely written to access logs, proxy
logs, and error reports, and the HDP-Token value
contains the principal object and the full chain.
Deployments SHOULD configure logging to treat
HDP-Token as sensitive, as they would an
Authorization header.¶
When token size is a concern (e.g., long chains), the token
MAY be stored server-side and referenced using the
HDP-Token-Ref header. The reference is either the
token's token_id, or a content-addressed reference:
the string sha256: followed by the base64url encoding
(no padding) of the SHA-256 digest [RFC6234] of
the token's canonical JSON serialization per RFC 8785.¶
A recipient resolving a content-addressed reference MUST
validate the resolved token's input representation, serialize
the complete token (including signature and all hop
signatures) with RFC 8785, encode the result as UTF-8, compute
SHA-256, and compare the digest with the reference. The digest
in the reference MUST be exactly 32 bytes encoded as canonical
unpadded base64url; malformed encodings or a digest mismatch
MUST cause rejection. The comparison commits to canonical JSON,
not to whitespace or member ordering in the stored serialization.
For a UUID reference, the resolved header.token_id
MUST identify the same UUID; equality is determined by the
UUID's 128-bit value, not hexadecimal letter case. The recipient
MUST reject a mismatch. Successful reference resolution MUST
be followed by integrity verification
(Section 5); a valid signature alone does not
establish that the requested reference was resolved correctly.¶
Implementations using token-by-reference MUST secure the
token store and use transport-layer security (TLS) for all
reference resolution. The store MUST be write-once per
reference: once a reference resolves to a token, it MUST NOT
later resolve to a different one. Here, sameness means an
identical complete canonical JSON token, not an identical
token_id alone. A UUID reference therefore identifies
one immutable snapshot, optionally the final record. It MUST
NOT be used as a mutable pointer to the latest chain. Because
extension preserves token_id, subsequent snapshots
MUST use new content-addressed references when transported by
reference; the previous UUID mapping remains unchanged.¶
The write-once requirement exists because a reference by
token_id is a substitution point. A different but
validly signed token stored under the same token_id
passes integrity verification and presents the wrong
provenance. Session binding narrows the set of tokens
that could be substituted but does not eliminate it. A
content-addressed reference removes the substitution point,
when the recipient performs the required digest check, and SHOULD be
preferred where the resolving party does not control the
store. A content-addressed reference changes each time the
chain is extended, which is the intended behaviour: each
extension is a different record.¶
A store that holds every snapshot of a token in full repeats the chain prefix on each extension, so keeping all the snapshots of an n-hop chain costs storage on the order of n squared hops. A store MAY instead hold a token as hash-linked entries:¶
chain.¶
prev, the content-addressed reference
(Section 8.2) of the snapshot it
extends, and hop, the one hop appended.¶
{
"prev" : "sha256:<digest of the snapshot this entry extends>",
"hop" : { "seq": 3, "agent_id": "...", "hop_signature": "..." }
}
¶
The store keeps each entry under the content-addressed reference
of the complete snapshot it produces: the token that results
from appending hop to the snapshot named by
prev. References keep their meaning. A
content-addressed reference always identifies a complete token,
and resolving one from a hash-linked store means reconstructing
that token by following prev back to the base entry,
appending the hops in order, and checking the digest as
Section 8.2 requires. A store MAY return
the entries in place of the complete token; the recipient then
reconstructs the token and performs the same check. The layout
of a store's entries is a storage matter and is not part of the
token wire format.¶
Hash-linking saves storage, not verification. A hop signature covers every hop before it (Section 4.2), so an auditor still has to fetch and check every hop up to the snapshot being verified.¶
Records also grow in a second direction. An action may take as
an argument something delegated under another task, and a full
audit of the action then involves that task's record as well:
with chains of five hops, an action with k such arguments brings
on the order of 5 * (1 + k) hops into its audit. Where a hop's
action takes such an argument, its action_summary
SHOULD refer to the other record by content-addressed reference
rather than embedding it.¶
Issuers that wish to publish their Ed25519 public keys for
automated discovery SHOULD serve a JSON document at
/.well-known/hdp-keys.json with the following
structure:¶
{
"keys": [
{
"kid" : "alice-signing-key-v1",
"alg" : "Ed25519",
"pub" : "<base64url-encoded 32-byte Ed25519 public key>"
}
]
}
¶
This endpoint is a discovery convenience only. It is not part of verification, which takes the issuer's public key as an input and remains fully offline (Section 10.9). A verifier that has obtained the key by other means has no reason to consult it.¶
This format is intentionally minimal. Implementations MAY
extend it with additional metadata. The alg field
MUST be "Ed25519" for HDP v0.1 keys. Consumers MUST
reject entries with unrecognized alg values.
Consumers MUST validate that the decoded public key is
exactly 32 bytes.¶
The principal object may contain PII (email address,
display name). Issuers SHOULD apply the principle of minimum
disclosure when constructing tokens that will traverse multiple
agents. Specifically:¶
id_type: "opaque" with an application-internal
identifier rather than embedding the user's email address in
tokens that will be sent to third-party agents.¶
display_name when the receiving agent does not
require a human-readable identity.¶
The token structure separates the identity fields
(principal) from the audit-relevant fields
(header, scope, chain). Implementations
MAY strip the principal object when forwarding tokens
to agents that do not require principal identity. A stripped
token is no longer verifiable: its root signature can no longer
be checked, so nothing binds its header, scope, or chain to the
principal's authorization. Stripped tokens MUST be marked as no
longer verifiable and MUST NOT be reported as having valid
integrity.¶
The same principle applies to the agent_id field in hop
records (Section 3.4). An agent_id need not
be meaningful to anyone but the delegator that assigned it.
This is sufficient because accountability in a delegation
chain is recursive: a delegator is responsible for how its
direct delegate uses the delegation, even when the use occurred
further down the chain, and that delegate is in turn
responsible for its own direct delegate. A verifier or auditor
therefore never needs to resolve an agent_id
globally. It needs the delegator at each step to be able to
identify the party it delegated to, and the agent_id
and its action_summary are bound into the signed chain
for exactly that purpose.¶
Which identifier to use is context dependent, and HDP does not prescribe one. Non-exhaustively: a widely known identifier, such as an enterprise employee or service number, suits deployments where correlation is not a concern; an identifier meaningful only to the delegator suits deployments where an observer must be prevented from correlating requests across chains; an identifier meaningful only to the audit system suits deployments that must hide the organisation's structure from everyone else who sees the token; a DID ([W3C.DID]) suits deployments where a trusted authority exists to assert claims about it. An issuer or extending agent MAY use a fresh identifier for every delegation. Opaque identifiers hide who is in a chain but not its length: a chain of them still shows how many hops a task took (Section 10.5).¶
HDP v0.1 offers no field-level confidentiality: a token is
either conveyed whole or stripped, as above. Earlier revisions
gave two reasons for not specifying encryption of
principal fields: the keys in circulation are Ed25519
signing keys rather than encryption keys, and the set of
verifiers was open, so there was no defined party to encrypt
to. The second reason no longer holds. The reader of a token is
the audit system (Section 1.1), so fields
the agents do not need, such as principal fields, could
be encrypted to it, much as SAML 2.0 allows individual
attributes in an assertion to be encrypted. The cost is key management: the
audit system needs an encryption key pair, distinct from any
signing key, whose public key issuers can obtain and whose
secret key is retained for as long as the records are. Field-level
encryption to the audit system is therefore a candidate for a
future version. Selective disclosure of principal fields and of
individual hops, which would allow a token to be verified with
parts withheld, is also planned for a future version.¶
HDP tokens may constitute personal data under applicable privacy
regulations (e.g., GDPR Article 4(1)) when the
principal.id or principal.display_name fields
contain directly or indirectly identifying information.¶
Implementations SHOULD:¶
principal.id where
possible, maintaining a separate mapping that can be
destroyed independently of the token audit log.¶
Encrypting stored tokens does not by itself discharge an erasure obligation, since the ciphertext remains personal data for as long as the key exists. Destroying the key (crypto-shredding) is a recognised technique for rendering retained tokens unreadable and MAY be used together with the mapping-destruction approach above.¶
The optional principal.poh_credential field MAY carry
a credential attesting that the principal is a human (e.g., a
Worldcoin World ID proof, a CAPTCHA session token, or a
biometric attestation identifier). The HDP protocol does not
define the semantics of this field; verification is entirely
application-defined.¶
An auditor that checks the credential reports the result separately from record integrity (Section 5). A check made at audit shows the credential's status at that time, not when the token was issued; evidence of the earlier status has to be retained when that earlier check is made. The verifier callback SHOULD be idempotent and SHOULD NOT have side effects.¶
HDP is designed to provide provenance and tamper evidence, not runtime enforcement. An agent that exceeds its declared scope is still a bad actor; HDP creates an evidence trail, not a capability boundary. Applications requiring runtime enforcement MUST implement it in their own access control mechanism and MUST NOT use the HDP token as an input to it. HDP is not an authorization protocol (Section 1.1); the properties discussed below are properties of the record: who could have produced it, whether it has been altered, and what it does and does not establish.¶
A forged token (one whose header, principal,
or scope fields do not match the original issuance) will
fail Step 2 of integrity verification (root signature check).
The security of this step relies on the unforgeability of Ed25519
signatures and the collision resistance of SHA-512 (used
internally by Ed25519). An attacker who does not possess the
issuer's secret key cannot produce a valid root signature for
a modified token.¶
Modification, reordering, or removal of any non-trailing hop is detectable: it either breaks the hop sequence check (Step 3) or invalidates the hop signatures of all subsequent hops (Step 4), because each hop signature covers all previous hops and the root signature. Insertion of a fabricated hop will similarly fail unless the attacker possesses the issuer's secret key. Removal of one or more trailing hops is a distinct case that these checks do not detect; see Section 10.4.¶
Each hop signature covers only the hops that precede it and the
root signature. Consequently, deleting one or more hops from the
end of the chain, or presenting an earlier and shorter
copy of a token, yields a token that still passes integrity
verification. HDP therefore provides tamper evidence
for the hops that are present, but does not by itself prove that
the chain is complete.¶
Relatedly, a non-cooperating or compromised agent can decline to append a hop for an action it takes; HDP records declared delegation actions and cannot compel an agent to record one. HDP is an evidence trail, not an enforcement mechanism (Section 10.1).¶
Where the receiving side can authenticate the presenter (for
example, because the transport identifies the calling agent),
it SHOULD record the presenter's identity with the token it
received, and an auditor SHOULD compare the final hop's
agent_id with that recorded presenter. This is cheap
and exposes one truncation case: a third party presenting a
shorter, earlier copy of the token, whose final hop names
someone else. Capability systems impose the same requirement at
invocation: UCAN Invocation requires the delegation chain to end
at the invoker, and a ZCAP-LD invocation proof is rooted in the
invoker's key.¶
The presenter check does not make the chain complete. In a
capability chain, truncation gains an attacker nothing beyond
what the presenter check catches, because authority only
narrows toward the tail: a truncated prefix is usable only by
the delegatee of its last remaining hop, who holds that
authority legitimately. HDP hops record actions, not grants,
and there is no attenuation; a truncated chain carries the full
original scope. The case HDP must consider is an
intermediate agent that deletes the hops appended after its
own, in order to hide what its sub-agents did. After
truncation that agent genuinely is the presenter, and the
presenter check passes.¶
Where the deployment uses a capability system such as UCAN or ZCAP-LD, the certificates presented at the resource are a better record of exercised authority than anything HDP carries. The resource sees every certificate in each chain presented to it, and no intermediate agent can remove one from the resource's log. HDP should not duplicate that record. What HDP adds on such a deployment is the part that never produces a certificate: what the principal asked for and how each hop read it, which can travel in the certificates' own metadata (Section 11).¶
Concurrent extensions from the same prefix can produce two
valid branches with the same token_id, hop count,
and final agent_id, but different recorded actions.
A hop count or presenter check cannot distinguish them.
Integrity verification checks the supplied branch; it does not
discover other branches or select a uniquely final one.¶
Deployments that require one linear record per token MUST serialize extensions at the issuer. The issuer MUST atomically check that the submitted prefix matches its accepted chain head and advance that head when committing an extension. A stale prefix MUST be rejected for reconciliation against the current head. An already signed hop cannot simply be transplanted onto another branch; extending the reconciled prefix requires a new signature. Retries SHOULD return an already committed result when the application identifies the same extension request. Deployments that intentionally allow branching MUST retain and identify the branches separately and define how their audit process accounts for them. HDP v0.1 defines no branch merge operation. Issuer serialization is state used for construction, not a network dependency of verification.¶
Applications requiring evidence of a particular observed or
final record SHOULD retain an authenticated receipt or
settlement record binding the token_id,
session_id, complete token digest as defined in
Section 8.2, observation time, and
observing party. It MUST distinguish an observed snapshot from
a claimed final record. A verifier relying on that receipt MUST
validate its authenticity and compare the token digest. A hop
count MAY be included for diagnostics but MUST NOT be treated
as a substitute for the digest. The receipt establishes which
branch was observed or finalized under the application's policy;
it does not prove that no unrecorded action or undisclosed
branch exists. Off-record delegation remains a separate
limitation (Section 10.5). These
receipts are application-layer artifacts, not new token fields.¶
Limiting delegation depth is an anti-pattern for authorization. Nothing can prevent an agent from sharing a credential with another, so a limit on how far authority may be delegated does not stop delegation; it only stops the delegation from being visible. Capability systems rely instead on holding whoever shares a credential responsible for everything done with it, in the hope that this gives the sharer reason to delegate properly.¶
A limit on what a record holds is different, because the record
confers no authority. scope.max_hops
(Section 3.3) sets how many hops the record holds.
Once the chain is full it is not extended, and responsibility
for anything delegated beyond that depth rests with the agent
that appended the final hop, by the recursive accountability
described in Section 9.1. That agent is
usually the right one to hold responsible: an agent at the third
hop that starts a swarm of a hundred sub-agents is accountable
for all of them, whether or not each has a hop of its own. An
issuer MAY therefore set max_hops to bound the size of
a record, or to limit how much of an organisation's structure a
record exposes. Opaque identifiers
(Section 9.1) hide who is in a chain but
not how deep it goes; max_hops limits the depth shown.¶
Earlier revisions argued against max_hops: where an
application gated actions on a valid chain, an exhausted budget
pushed an agent that still needed to delegate to do so without
appending a hop. That argument depended on the token being an
input to access decisions. It no longer is
(Section 1.1). A full chain stops no action,
so reaching max_hops gives no agent a reason to hide
what it does.¶
Delegation without appending a hop remains possible whatever
max_hops says, because nothing in HDP forces an agent to
extend the token. A planner can hand its token unchanged to a
sub-agent, or pass the task along in-process, and the
sub-agent's actions then go unrecorded or are recorded as the
planner's. The chain still verifies, because verification checks
only what was recorded. HDP cannot prevent this on its own. Two
things limit it: the agent that passed the task on without a hop
answers for what was done with it, and a recording component
outside the agent's control (Section 3.4) records the
hops an agent would leave out.¶
Independently of max_hops, an auditor MAY flag chains
longer than a locally configured limit, as a heuristic it can
change without reissuing tokens. Chains are expected to grow
longer as agents start agents, and
Section 8.3 describes how a store can
hold them without repeating each chain prefix.¶
An agent may hold more than one valid HDP token whose
scope covers the same resource: for example, one
issued for Alice and one issued for Carol, each authorizing an
update to the same dataset. Applications MUST bind an action or
attempted action to the task and token that actually triggered
it, and agents MUST record it under that context. They MUST NOT
select a different token merely because its scope would make
the action appear authorized. A deviation from the triggering
token's scope SHOULD be recorded under that token, explicitly
identified as an attempted, blocked, or observed violation in
action_summary. Recording the deviation does not amend
scope or assert that the principal approved it. If the
triggering context is unknown, the application MUST preserve
that uncertainty in its audit record rather than assign an
unrelated principal.¶
HDP cannot detect a violation of this rule. A hop appended to the wrong token passes integrity verification, because verification establishes that the hop was recorded, not that it was recorded in the right place. The consequence is borne at audit. An update performed in Carol's task but recorded under Alice's token fits Alice's scope, so nothing in the record gives it away: it implicates Alice and leaves Carol's token silent. An action recorded under a token whose scope does not cover it at least shows up as a deviation; the harmful case is an action both scopes cover. Equally, an action that occurred in Alice's task belongs in Alice's record even if it exceeds her scope; it MUST NOT be moved to Carol's token to make it appear permitted. A signed record alone cannot prove correct task attribution, and inclusion of an action MUST NOT be interpreted as proof that the principal approved it.¶
Where more than one task could legitimately initiate an
action, selecting the initiating task is application policy.
Applications SHOULD define and record that choice before
execution, together with a request or event identifier. Once
selected, the triggering context governs provenance even if
the action deviates from its scope. Joint approval
(Section 7) does not address this case:
it covers tokens linked by parent_token_id that share a
session_id, and the tokens here are unrelated. The
neighbouring question of how a service decides which of several
grants applies to a request is an authorization-layer question
and is outside HDP (Section 1.1).¶
Prompt injection attacks attempt to cause an agent to act as if it received instructions from a legitimate principal, when in fact the instructions originate from adversarial content in the agent's environment (e.g., a malicious web page or document). HDP does not detect or prevent this attack.¶
Knowing whether a particular use of a permission went against
what the principal wanted is a hard problem, and HDP does not
attempt it. What HDP does is record every use, including
attempted and blocked ones, and leave the judgement to the
principal or an auditor, who can read the principal's request
and each hop's reading of it side by side. An agent or recording
component (Section 3.4) SHOULD record each attempted
action, any deviation from the declared scope it noticed, and
whether the action was blocked, in action_summary under
the triggering task's token. Any blocking is done by the
application's own access control, not by HDP, and blocking an
action MUST NOT suppress its record. A violation observed after
execution SHOULD likewise be recorded as an observed violation,
without claiming that the principal approved it or that the
signature proves execution. The hop timestamp remains the
extension time, not a backdated event time. If the token cannot
be extended because its chain has reached max_hops, the
application SHOULD retain an integrity-protected incident record
linked to the token digest and the triggering request. HDP v0.1
adds no status field for this purpose; the distinction is
explicit in the declaration.¶
The record depends on agents, or recording components, actually recording actions. An agent that omits a hop is discussed in Section 10.4 and Section 10.5.¶
The security of all HDP guarantees depends on the confidentiality of the issuer's Ed25519 secret key. Implementations MUST:¶
kid, and retain every public key an auditor may need,
with its compromise history, for the audit retention period
(Section 5.1). This does not require
retaining retired secret keys.¶
A correct implementation of integrity verification (Section 5) requires no network calls, no registry lookups, and no third-party contact. The complete trust state it requires is the issuer's Ed25519 public key (32 bytes).¶
This guarantee is a property of the verification procedure, not of the single-key signing model of v0.1. Per-agent hop signing on the pattern described in Section 4.2 would preserve it, since the verifier would still resolve only the issuer's key out of band.¶
This guarantee lets an auditor verify records long after they were made, in an air-gapped environment, and without the issuer's cooperation beyond having published its key.¶
On a deployment that already uses a capability system, the certificates presented at a resource are a record of the authority each agent exercised (Section 10.4). What they do not usually record is what the principal asked for and how each agent read the task. This section describes carrying that content in the certificates' own metadata, in place of a separate HDP token. It is a sketch offered for review rather than a complete profile, and the member names in it are provisional.¶
The certificates already record who delegated to whom, when, what authority was passed on, when it expires, and the chain back to the root. The carried content repeats none of that.¶
The principal's request does not usually enter at the root. A service that controls a resource typically delegates first to its own software, which then delegates to an agent working on the principal's behalf. The request enters the chain at that agent, the one the principal prompted, and the delegations made before it carry no HDP content, since their delegators never saw the request. The carried content consists of the following members:¶
Only in the first certificate signed by the principal or by the agent the principal prompted, whether a delegation or, if that agent acts itself, an invocation:¶
intent: the principal's request, as in
scope.intent.¶
principal: the principal's identifier and its
type, as in principal.id and
principal.id_type, subject to
Section 9.1. OPTIONAL.¶
session: the session in which the principal made
the request, as in header.session_id, so that the
chain can be associated with the session's other
records.¶
limits: anything the principal declared that the
capability cannot express, such as the
data_classification, network_egress, and
persistence values of the scope. OPTIONAL. Like the
scope, these record a declaration and restrict nothing.¶
In that certificate and every delegation below it:¶
summary: the delegating agent's reading of the
task it passes on, as it would appear in
action_summary. An auditor finds drift by comparing
the summaries with intent.¶
agent: the delegating agent's role, as in
agent_type, and optionally a fingerprint of its
model or binary, as in agent_fingerprint. The
certificate identifies the delegator by its key, not by what
was running behind it.¶
recorder: the component that wrote the summary,
when it was not the agent itself (Section 3.4).
OPTIONAL.¶
summary, agent, and
recorder members for the invoking agent, with the
summary stating whether the action was attempted, blocked, or
observed as a deviation (Section 3.4). The invocation
already records what was asked of the resource, but not the
agent's account of it.¶
Each item is signed by the party whose certificate carries it. This gives the effect of per-agent signing (Section 4.2) with the capability system's existing keys, and the chain presented at the resource ends at the invoker. Two properties of the standalone token do not carry over: a single issuer's signature over the principal's request, and a record of delegations that were never invoked, since a resource sees only the chains presented to it. As with the standalone token, the carried content is a record and MUST NOT be used as an input to any access decision (Section 1.1).¶
UCAN 1.0 delegations [UCAN-DELEGATION] and
invocations [UCAN-INVOCATION] each have an
optional meta field, a map that the issuer signs with
the rest of the payload. The delegation specification describes
meta as asserted, signed data that is not delegated
authority, which is the status HDP content needs. This profile
places HDP content under a single meta key,
hdp. The example is shown in JSON for readability;
UCAN 1.0 payloads are encoded in DAG-CBOR.¶
"meta": {
"hdp": {
"v" : "0.1",
"intent" : "Analyze Q1 sales data and report.",
"principal" : { "id": "usr_alice_opaque", "id_type": "opaque" },
"session" : "sess-20260326-abc123",
"summary" : "Decompose task; delegate the query to sub-agent.",
"agent" : { "type": "orchestrator" }
}
}
¶
The intent, principal, session, and
limits members appear only in the first certificate
signed by the principal or by the agent the principal prompted.
The summary and agent members appear in that
certificate and every one below it, including the invocation, as
does recorder when present. An invocation's
prf field lists the delegations it relies on, so a
resource that retains its invocations together with their
delegations holds the whole record, and UCAN receipts can record
the result of each invocation alongside it.¶
A ZCAP-LD [W3C.ZCAP-LD] delegated capability is a
JSON-LD document signed by the delegator with a Data Integrity
proof. An invocation carries the delegated capability, and its
capabilityChain embeds the parent capability in full,
so content placed in each delegated capability would be signed
by its delegator and reach the resource with the chain.¶
The current ZCAP-LD draft does not say where such content
belongs. It forbids additional fields in a root capability, says
nothing either way about additional fields in a delegated
capability, and provides the caveat property only for
restrictions on use. HDP content is not a restriction, and MUST
NOT be expressed as a caveat, since a caveat is an input to the
access decision. The candidate this document puts forward is an
additional property, hdp, on each delegated capability,
with the same members as the UCAN form and defined in a JSON-LD
context listed after the ZCAP-LD context. A root capability can
carry no other fields, so a principal who controls the root
records the request in the first capability the principal
delegates. Whether ZCAP-LD
implementations accept a delegated capability with such a
property, and whether a context is the right way to define it,
are open questions on which review is sought. So is where the
invoking agent's content belongs: an invocation made with an
HTTP signature has no document to carry it.¶
This document requests registration of the following HTTP header fields in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" maintained at <https://www.iana.org/assignments/http-fields/>.¶
This document requests registration of the
application/hdp-token+json media type in the "Media
Types" registry, following the procedures of
[RFC6838].¶
This document requests registration of the following entry in the "Well-Known URIs" registry, per [RFC8615].¶
The Intent Provenance Protocol [I-D.haberkamp-ipp] and HDP address the same root problem with different architectural trade-offs. The key differences are:¶
offline_grace_period_ms
and the offline duration remains within that period.
Otherwise IPP prohibits proceeding. HDP has no revocation: an
HDP token is a record and is never honoured or refused
(Section 1.1), so there is nothing to
revoke. Withdrawing authority belongs to the access control
mechanism HDP travels alongside.¶
genesis object (the Genesis
Seal), a cryptographic
artifact linking every token to the specification author's
public key at
https://ipp.khsovereign.com/keys/founding_public.pem.
Self-hosted IPP deployments are cryptographically bound to
this third-party key. HDP tokens carry no genesis seal and no
spec-level attribution; any organization can issue and verify
HDP tokens without anchoring to a third party.¶
id_type: "opaque" as a first-class
option, making DID infrastructure optional rather than
required.¶
These are design choices, not defects. Deployments with reliable connectivity to a revocation service, existing DID infrastructure, and a requirement for revocation across token ancestry may prefer IPP. Deployments that prioritize offline operability, self-sovereignty, and minimal infrastructure may prefer HDP.¶
OAuth 2.0 Token Exchange [RFC8693] defines a mechanism for exchanging one security token for another, including delegation and impersonation use cases. HDP and RFC 8693 are complementary rather than competing: RFC 8693 governs access token issuance and delegation in an OAuth 2.0 authorization server context, while HDP governs the provenance record that travels with an agentic task regardless of the authentication mechanism used.¶
HDP tokens do not replace OAuth access tokens. An agent framework MAY use OAuth 2.0 for resource authorization and HDP for delegation provenance simultaneously.¶
JSON Web Token [RFC7519] provides a general-purpose signed claims format. HDP differs from JWT in three respects:¶
chain) that has no equivalent in the
JWT standard claims set.¶
UCAN [UCAN] defines a capability-based authorization token system with chained delegation. HDP and UCAN share the concept of delegation chains but differ significantly in scope: UCAN is a general capability authorization system, while HDP is specifically a provenance record for human-authorized agentic tasks. HDP makes no claims about capability enforcement; UCAN tokens carry executable capabilities that are enforced by receiving systems.¶
A UCAN delegation records who delegated what to whom, and UCAN's
Invocation and Receipt objects record individual invocations and
their results. A resource can retain them, and then holds a
record of the authority exercised. What those objects do not record by default is the
principal's request and each agent's reading of the task. A UCAN
deployment can carry that content in its meta fields
(Section 11.1) rather than in a
separate HDP token. The standalone HDP token is intended for
deployments with no capability chain to carry it, such as those
using bearer tokens or API keys, or handing tasks between agents
in-process.¶
ZCAP-LD [W3C.ZCAP-LD] expresses delegated authorization capabilities as Linked Data, with invocation and delegation rooted in a controller's key. As with UCAN, a resource that retains the capability chains presented to it holds a record of the authority exercised. What the chain does not record is the principal's request or each agent's reading of the task. HDP neither defines nor enforces capabilities. Section 11.2 discusses carrying HDP content in delegated capabilities; the form it takes there is an open question.¶
The Open Digital Rights Language (ODRL)
[W3C.ODRL] is a W3C Recommendation for expressing
permissions, prohibitions, and constraints. Several fields in
HDP's scope object (Section 3.3) overlap with
concepts ODRL already defines: authorized_tools and
authorized_resources correspond to ODRL actions and
targets, and network_egress and persistence
map to ODRL permissions or prohibitions.¶
HDP v0.1 deliberately retains a small, self-contained
scope object rather than embedding an ODRL policy. The
trade-off is explicit: the minimal object keeps tokens compact
and implementable with only JSON and Ed25519, at the cost of the
vocabulary reuse, policy composability, and tooling
interoperability that ODRL provides. Deployments that already
reason over ODRL policies will require a separate mapping to
interpret HDP scopes.¶
A further limitation of the v0.1 scope object is that
it is fixed at issuance. HDP has no attenuation: a delegate
cannot narrow the scope at its own hop, because hops record
actions rather than grants and a hop record has no field in
which a narrower scope could be expressed. A delegate that
wishes to pass on less than it received must obtain a new
token from the issuer with a narrower scope. Per-hop
caveats, which only the verifier and any attenuating agent
would need to interpret, are planned for a future version.¶
Because the chain-of-custody mechanism is payload-agnostic
(Section 1.5), a future HDP profile MAY carry an
ODRL policy as its payload in place of the native scope
object. Such a profile would gain a natural binding to the
Verifiable Credentials Data Model 2.0
[W3C.VC-DATA-MODEL-2.0], whose termsOfUse
property can carry ODRL policies.
This binding is identified as future work and is not specified in
this document.¶
The following is a complete HDP token with a two-hop delegation
chain, for illustrative purposes. Signature values are truncated.
The scope lists a resource for each tool that acts on
one, and each hop names the resource it declares acting on;
Section 3.3 explains why v0.1 cannot bind tools to
resources structurally.¶
{
"hdp": "0.1",
"header": {
"token_id" : "550e8400-e29b-41d4-a716-446655440000",
"issued_at" : 1711483200000,
"expires_at" : 1711569600000,
"session_id" : "sess-20260326-abc123",
"version" : "0.1"
},
"principal": {
"id" : "usr_alice_opaque",
"id_type" : "opaque",
"display_name" : "Alice Chen"
},
"scope": {
"intent" : "Analyze Q1 sales data and report.",
"authorized_tools" : ["database_read", "file_write"],
"authorized_resources": ["db://sales/q1-2026",
"file://reports/"],
"data_classification" : "confidential",
"network_egress" : false,
"persistence" : true,
"max_hops" : 10
},
"chain": [
{
"seq" : 1,
"agent_id" : "orchestrator-v2",
"agent_type" : "orchestrator",
"timestamp" : 1711483260000,
"action_summary" : "Decompose task; delegate to sub-agents.",
"parent_hop" : 0,
"hop_signature" : "base64url-sig-1..."
},
{
"seq" : 2,
"agent_id" : "sql-agent-v1",
"agent_type" : "sub-agent",
"timestamp" : 1711483320000,
"action_summary" : "Execute read query on db://sales/q1-2026.",
"parent_hop" : 1,
"hop_signature" : "base64url-sig-2..."
}
],
"signature": {
"kid" : "alice-signing-key-v1",
"alg" : "Ed25519",
"value" : "base64url-root-sig..."
}
}
¶
Alan Karp reviewed successive revisions of this document in
detail, most recently in a section-by-section review of -02 on the
W3C Credentials Community Group list and the discussion that
followed. He pointed out that relying on the token before an
action would add a second access control mechanism, a well-known
hazard, which led to the removal of live use in this revision
(Section 1.1). His reviews also shaped the
following: the treatment of recording depth
(Section 10.5); the recursive accountability
argument, the guidance on delegate identifiers, including
identifiers known only to the audit system, and the case for
field-level encryption (Section 9.1);
recording by a component outside the agent's control and the
free-form agent_type (Section 3.4); the
planned nested permission structure and the critique of the
coarse scope values (Section 3.3); carrying
HDP content in capability certificates
(Section 11) and the view that such
certificates are the better record of exercised authority
(Section 10.4); the chain-length concern
behind hash-linked snapshots
(Section 8.3); the correction to the
stated cost of single-key signing, the case for keeping issuer
signing as the baseline, and support for a fresh key per
delegation (Section 4.2); the revised
attribution example (Section 10.6); the
position that HDP records every use and leaves the judgement to
the user (Section 10.7); the use of
"secret key" in place of "private key"; and the insistence that
this document say plainly what HDP is not. Acknowledgment does not
imply endorsement of the design choices that remain.¶
Brigitte Qirong LI supplied the characterization of a single-key hop signature as recording a delegation rather than evidencing consent to it (Section 4.2), and the exchange on the W3C Credentials Community Group list sharpened the analysis of chain truncation (Section 10.4).¶
Bob Wyman and sankarshan mukhopadhyay reviewed the initial revision on the same list; their comments shaped Section 1.5 and Section 13.6.¶
This section will be removed before publication as an RFC.¶
expires_at and
session_id remain in the wire format as record metadata
(Section 3.1). Verification is now integrity
verification in five steps (Section 5), and
audit tooling reports integrity, the recording period, the
session, and linked-record relationships separately
(Section 5.1). max_hops is kept
and redefined as the depth the record holds, with the agent at the
last recorded hop accountable for delegation beyond it
(Section 10.5); -02 argued against the
field. Added carrying HDP content in UCAN and ZCAP-LD metadata
(Section 11) and hash-linked snapshots
(Section 8.3). Issuer signing remains
the baseline, with per-agent signing planned as an option
(Section 4.2). Re-authorization is recast as
superseding records (Section 6), and
multi-principal delegation as joint approval, with the untagged
parent_token_id stated as a known weakness
(Section 7). Recommended that a component
outside the agent's control record hops, and made
agent_type free-form (Section 3.4). Described
the planned nested permission structure (Section 3.3).
Revised the rationale for the query-parameter ban
(Section 8.1), the treatment of stripped tokens
and field-level encryption (Section 9.1),
the attribution example (Section 10.6),
prompt injection (Section 10.7),
and the UCAN and ZCAP-LD comparisons. Replaced "private key" with
"secret key". The token structure and signature payloads are
unchanged and remain HDP v0.1; agent_type now accepts any
string.¶
scope field descriptions, the verification pipeline,
and the transport text with it. Revocation is now normative: a
verifier MUST support verifier-local revocation by
token_id, checked at Step 2 (Section 10.6 of -02);
re-authorization is described as lineage rather than revocation
(Section 6); the 24-hour default lifetime
is removed (Section 10.5 of -02). Corrected the
stated cost of single-key hop signing and described what a v0.1
hop signature does and does not attest
(Section 4.2). Hop timestamp monotonicity is
now a MUST (Section 4.3). Added
Section 10.5 (then titled delegation budgets
and off-record delegation), Section 10.6
(attribution across concurrent tokens), a presenter check and a
completeness analysis in Section 10.4,
recursive accountability and delegate-identifier guidance in
Section 9.1, a content-addressed
token-by-reference option with a write-once requirement
(Section 8.2), a composition-versus-
chaining rationale (Section 7), and an
attenuation limitation (Section 13.6).
Noted that authorized_tools and
authorized_resources are unbound lists
(Section 3.3) and corrected the Appendix A example
accordingly. Retargeted [HDP-SPEC]. Added an
Acknowledgments section. A subsequent consistency review added
historical audit verification distinct from live acceptance;
explicit recording of out-of-scope attempts and observed violations;
issuer serialization and digest-bound receipt guidance for forks;
mandatory reference integrity checks and immutable UUID snapshots;
explicit retained context for parent-link meaning; exact integer
bounds and input validation; and corrections to the IPP revocation
comparison. The token structure and signature payloads are
unchanged and remain HDP v0.1; input constraints and verifier
requirements have been tightened.¶
termsOfUse alignment note, and
ZCAP-LD; the UCAN comparison identifies the execution audit trail as
HDP's distinguishing contribution. Added Section 1.5
(payload-agnostic chain-of-custody with agentic delegation as the
reference profile). Corrected root signature verification to reset
chain to empty before canonicalization, matching the
signing procedure, and clarified that in v0.1 the issuer produces
all root and hop signatures with a single key. Added
Section 10.4 (chain truncation and
completeness), a revocation section (removed in -03),
session_id entropy guidance, and per-hop opaque-identifier
privacy guidance (Section 9.1). The
verification pipeline now also checks header.version,
signature.alg, and parent_hop validity. Completed
the IANA media-type registration template and added a Well-Known URI
registration. Added missing normative and informative references.
Renamed the HTTP header fields from X-HDP-Token and
X-HDP-Token-Ref to HDP-Token and
HDP-Token-Ref ([RFC6648]). Editorial
corrections. The token wire format is unchanged and remains HDP
v0.1; the HTTP header field names changed.¶