<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     docName="draft-prakash-aip-02"
     category="std"
     submissionType="IETF"
     consensus="true"
     sortRefs="true"
     symRefs="true"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="AIP">Agent Identity Protocol (AIP): Verifiable Delegation for AI Agent Systems</title>

    <seriesInfo name="Internet-Draft" value="draft-prakash-aip-02"/>

    <author initials="S." surname="Prakash" fullname="Sunil Prakash">
      <organization>Independent</organization>
      <address>
        <email>sunil@sunilprakash.com</email>
        <uri>https://sunilprakash.com</uri>
      </address>
    </author>

    <date year="2026" month="October" day="10"/>

    <area>Security</area>
    <workgroup>Network Working Group</workgroup>

    <keyword>AI agents</keyword>
    <keyword>delegation</keyword>
    <keyword>attenuation</keyword>
    <keyword>capability tokens</keyword>
    <keyword>MCP</keyword>
    <keyword>A2A</keyword>
    <keyword>WIMSE</keyword>
    <keyword>workload identity</keyword>

    <abstract>
      <t>This document specifies the Agent Identity Protocol (AIP), which
      conveys delegated authority along a chain of AI agents so that a
      relying party can verify, from the token and the issuer's public
      key, who granted the authority, through which agents it passed, and that no hop widened
      what it received. AIP addresses hops where no authorization server
      is on the path, such as one agent subdelegating to another. It is
      intended to compose with the AI Identity Management System (AIMS)
      framework, which covers hops where an authorization server is
      present. The document defines an encoding-neutral delegation chain
      model with a single attenuation invariant, a normative verification
      algorithm, and two encodings of the model: a chain of JSON Web
      Tokens, in which each link names the key of the next holder, and a
      Biscuit token with Datalog policy. Bindings are given for the Model
      Context Protocol (MCP), the Agent2Agent protocol (A2A), and generic
      HTTP.</t>
    </abstract>
  </front>

  <middle>
    <section anchor="introduction">
      <name>Introduction</name>

      <t>In a multi-agent system an orchestrator splits a task and hands
      parts of it to other agents, which may hand parts on again. The
      Model Context Protocol (MCP) <xref target="MCP"/> and the Agent2Agent
      protocol (A2A) <xref target="A2A"/> define how agents and tools
      connect. MCP specifies OAuth-based authorization for the hop between
      a client and a server, and A2A agents can declare authentication
      requirements. Neither carries a verifiable record of authority as it
      passes through several agents.</t>

      <t>The AI Identity Management System framework
      <xref target="I-D.ietf-wimse-aims"/> describes how agents obtain
      identifiers and credentials from the WIMSE architecture and how
      OAuth 2.0 mechanisms, including token exchange
      <xref target="RFC8693"/>, transaction tokens
      <xref target="I-D.ietf-oauth-transaction-tokens"/>, and identity and
      authorization chaining across domains
      <xref target="I-D.ietf-oauth-identity-chaining"/>, apply to agent
      authorization.
      In those mechanisms, narrowing is done by an authorization server or
      token service that evaluates its policy and issues a new token. The
      holder does not narrow its own token.</t>

      <t>Some hops have no such server. An agent that hands part
      of its task to a subagent, or to an agent in another organization
      with which no authorization server trust has been arranged, has to
      pass on a subset of its own authority directly. The relying party at
      the end of such a chain then needs to check, without calling back to
      the origin, that each hop narrowed or kept what it received.</t>

      <t>AIP specifies that check. For every action it lets a relying
      party answer three questions from the presented token: who
      authorized the action, through which delegation chain, and with what
      constraints at each hop. <xref target="chain-model"/> defines the
      chain and its attenuation invariant, <xref target="verification-algorithm"/>
      the verification algorithm, and <xref target="encodings"/> two
      encodings. <xref target="aims-relationship"/> describes how AIP is
      intended to sit alongside AIMS.</t>

      <t>This document cites <xref target="RFC8785"/> normatively as a
      downward reference <xref target="RFC8067"/>. The
      <xref target="BISCUIT"/> reference is pinned to tag v3.3 of the
      Biscuit specification.</t>

      <section anchor="requirements-language">
        <name>Requirements Language</name>
        <t>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 BCP 14 <xref target="RFC2119"/>
        <xref target="RFC8174"/> when, and only when, they appear in
        all capitals, as shown here.</t>
      </section>

      <section anchor="terminology">
        <name>Terminology</name>
        <dl>
          <dt>Delegation chain token:</dt>
          <dd>A token carrying an ordered list of links, L0 through LN,
          in one of the encodings of <xref target="encodings"/>.</dd>
          <dt>Authority link:</dt>
          <dd>L0, the link signed by the issuer's root key.</dd>
          <dt>Delegation link:</dt>
          <dd>Any link Li with i of 1 or more. N, the number of delegation
          links, is the delegation depth of the chain.</dd>
          <dt>Relying party:</dt>
          <dd>The party that verifies a chain before acting on it, for
          example an MCP server or an A2A agent.</dd>
          <dt>Effective value:</dt>
          <dd>For a link and a dimension, the value the link declares, or,
          if it declares none, the effective value of its parent. See
          <xref target="inheritance"/>.</dd>
        </dl>
      </section>
    </section>

    <section anchor="identity-scheme">
      <name>Identity Scheme</name>

      <t>AIP defines two identifier schemes for agent identity. Every
      issuer, delegator, and delegate in a chain is named by one of
      them.</t>

      <section anchor="dns-based">
        <name>DNS-Based Identifiers</name>
        <t>DNS-based identifiers follow the format:</t>
        <artwork><![CDATA[
aip:web:<domain>/<path>
        ]]></artwork>
        <t>Example: aip:web:example.com/agents/research-analyst</t>
        <t>DNS-based identifiers are suitable for long-lived agents with
        stable domain ownership. Identity documents are resolved via HTTPS
        at a well-known path.</t>
      </section>

      <section anchor="self-certifying">
        <name>Self-Certifying Identifiers</name>
        <artwork><![CDATA[
aip:key:ed25519:<multibase-encoded-public-key>
        ]]></artwork>
        <t>Self-certifying identifiers derive identity from the public key
        itself. They are suitable for ephemeral agents that do not require
        DNS infrastructure. The identifier is computed from the 32-byte
        Ed25519 <xref target="RFC8032"/> public key encoded as multibase
        base58btc (a "z" prefix followed by the base58btc encoding of the
        key).</t>
      </section>

      <section anchor="identity-document">
        <name>Identity Document</name>
        <t>Each agent with a DNS-based identifier MUST publish an identity
        document at:</t>
        <artwork><![CDATA[
https://<domain>/.well-known/aip/<path>.json
        ]]></artwork>
        <t>The identity document is a JSON object containing:</t>
        <ul>
          <li><tt>aip</tt>: Protocol version (MUST be "1.0")</li>
          <li><tt>id</tt>: The agent's AIP identifier</li>
          <li><tt>public_keys</tt>: Array of public key objects, each with
          <tt>id</tt>, <tt>type</tt>, <tt>public_key_multibase</tt> (the
          Ed25519 key in multibase base58btc, as in
          <xref target="self-certifying"/>), and optional
          <tt>valid_from</tt> and <tt>valid_until</tt></li>
          <li><tt>name</tt>: Human-readable agent name</li>
          <li><tt>delegation</tt>: Delegation preferences</li>
          <li><tt>protocols</tt>: Supported protocol bindings</li>
          <li><tt>revocation</tt>: OPTIONAL revocation endpoint (see
          <xref target="v7-revocation"/>)</li>
          <li><tt>document_signature</tt>: Ed25519 signature over the
          canonicalized document, encoded as base64url without padding
          (<xref target="RFC4648" section="5"/>)</li>
          <li><tt>expires</tt>: Document expiration timestamp</li>
        </ul>
        <t>The document MUST be self-signed. Verification uses
        JSON Canonicalization Scheme (JCS) <xref target="RFC8785"/>:
        remove the document_signature
        field, canonicalize the remaining JSON, and verify the Ed25519
        signature against a currently-valid public key.</t>
      </section>
    </section>

    <section anchor="chain-model">
      <name>Delegation Chain Model</name>

      <t>This section defines what a chain says, independent of how it is
      encoded. Each encoding in <xref target="encodings"/> MUST be parsed
      into this model before steps V3 through V6 of
      <xref target="verification-algorithm"/> are applied, so that the two
      encodings are verified by one set of rules.</t>

      <section anchor="links">
        <name>Links</name>
        <t>A chain is an ordered list of links L0, L1, ..., LN. L0 is the
        authority link. L1 through LN are delegation links. Each link has
        the following fields:</t>

        <table anchor="link-fields">
          <name>Link Fields</name>
          <thead>
            <tr><th>Field</th><th>L0</th><th>Li, i &gt;= 1</th></tr>
          </thead>
          <tbody>
            <tr><td>issuer</td><td>REQUIRED</td><td>REQUIRED, the delegate of L(i-1)</td></tr>
            <tr><td>delegate</td><td>REQUIRED in JWT; absent in Biscuit</td><td>REQUIRED</td></tr>
            <tr><td>tools</td><td>REQUIRED</td><td>OPTIONAL, inherits</td></tr>
            <tr><td>domains</td><td>OPTIONAL</td><td>OPTIONAL, inherits</td></tr>
            <tr><td>budget_ceiling</td><td>OPTIONAL</td><td>OPTIONAL, inherits</td></tr>
            <tr><td>expiry</td><td>REQUIRED</td><td>OPTIONAL, inherits</td></tr>
            <tr><td>context</td><td>absent</td><td>REQUIRED, non-empty</td></tr>
            <tr><td>principal</td><td>OPTIONAL</td><td>OPTIONAL, invariant once declared</td></tr>
            <tr><td>max_depth</td><td>REQUIRED</td><td>MUST NOT appear</td></tr>
            <tr><td>holder key</td><td>REQUIRED in JWT</td><td>REQUIRED in JWT</td></tr>
          </tbody>
        </table>

        <ul>
          <li>issuer and delegate are AIP identifiers
          (<xref target="identity-scheme"/>). The issuer of L0 is the party
          whose root key signs the chain. In the JWT chain encoding the
          verifier checks that the issuer of Li equals the delegate of
          L(i-1) (<xref target="jwt-v1"/>). In the Biscuit encoding L0 has no
          delegate, delegator and delegate are assertions
          (<xref target="biscuit-identity"/>), and this equality is not
          checked.</li>
          <li>tools is an allowlist of tool names or patterns
          (<xref target="matching"/>).</li>
          <li>domains is an allowlist of domain names.</li>
          <li>budget_ceiling is a non-negative integer number of cents
          (<xref target="budget-semantics"/>). The token does not name a
          currency; issuer and relying party agree on it out of band.</li>
          <li>expiry is a point in time after which the link conveys no
          authority.</li>
          <li>context is a human-readable statement of the purpose of the
          delegation.</li>
          <li>principal is the identifier of the party on whose behalf the
          chain acts.</li>
          <li>max_depth is a non-negative integer bounding N.</li>
          <li>holder key is the public key of the delegate, used to sign
          the next link and to prove possession
          (<xref target="proof-of-possession"/>). The Biscuit encoding has no
          holder key.</li>
        </ul>

        <t>When tools or domains is present in any link, it MUST be
        non-empty. An empty list is malformed, and a verifier MUST reject
        a chain containing one with <tt>aip_token_malformed</tt>. Absence
        means the link inherits; it never means "nothing permitted".</t>
      </section>

      <section anchor="inheritance">
        <name>Inheritance</name>
        <t>The effective value of a dimension at L0 is the value L0
        declares. The effective value at Li is the value Li declares if it
        declares one, and otherwise the effective value at L(i-1). The
        effective values at LN are the authority the chain conveys to its
        final holder.</t>
        <t>An effective domains value that is undefined at every link means
        the chain places no constraint on domains. The same holds for
        budget_ceiling and principal. A delegation link MAY declare a
        domains list, a budget ceiling, or a principal when no ancestor
        declares one; doing so narrows the chain.</t>
      </section>

      <section anchor="attenuation-invariant">
        <name>Attenuation Invariant</name>
        <t>For every i of 1 or more, and for every dimension (tools,
        domains, budget_ceiling, expiry, and principal), the effective value
        at Li MUST be narrower than or equal to the effective value at
        L(i-1): every tool Li permits MUST be permitted at L(i-1); every
        domain Li permits MUST be permitted at L(i-1); the budget ceiling at
        Li MUST NOT exceed that at L(i-1); the expiry at Li MUST NOT be later
        than that at L(i-1); and once a link declares a principal, no later
        link may declare a different one. A chain that violates this
        invariant at any hop conveys no authority, and verifiers MUST reject
        it as specified in step V4 of
        <xref target="verification-algorithm"/>.</t>
        <t>The invariant is a property of the capability content. It is not
        established by the signature structure of either encoding, and it
        is checked separately (<xref target="v4-attenuation-walk"/>).</t>
      </section>

      <section anchor="matching">
        <name>Wildcards and Matching</name>
        <t>A tools entry "*" covers every tool. Any other entry ending in
        "*" covers every tool whose name starts with the text before the
        "*"; for example "tool:*" covers "tool:search". Any other entry
        covers only the identical name.</t>
        <t>Narrowing compares an entry in Li against the entries at L(i-1)
        with the same rule, treating the Li entry as a literal string.
        An ancestor wildcard therefore permits a specific value or a
        narrower prefix pattern in a descendant ("tool:*" permits
        "tool:s*"). A specific value in an ancestor MUST NOT widen to a
        wildcard in a descendant: "tool:search" does not cover "tool:*",
        because "tool:*" does not start with "tool:search".</t>
        <t>Domains are matched exactly in this revision. There is no
        wildcard or suffix matching for domains.</t>
      </section>

      <section anchor="budget-semantics">
        <name>Budget Semantics</name>
        <t>Budget values in AIP tokens represent per-chain authorization
        ceilings, not running balances. A delegator asserts "I authorize up
        to this amount for this task" at delegation time.</t>

        <t>A budget ceiling is both declared and verified, and the two are
        distinct operations:</t>
        <ul>
          <li>Declared by the link that establishes it, as an integer number
          of cents.</li>
          <li>Verified structurally at every hop: a verifier MUST confirm that
          each declared ceiling is non-negative and does not exceed the
          effective ceiling of the parent link. A link that declares no
          ceiling inherits. This check is step V4 of
          <xref target="verification-algorithm"/>.</li>
        </ul>

        <t>What the token does not do is track cumulative spending. Nothing
        in a delegation chain records how much of a ceiling has been
        consumed, and a verifier evaluating a single request cannot know.
        Enforcement of actual spend against a ceiling is out of band, and is
        the responsibility of the orchestration platform at dispatch
        time.</t>

        <t>Implementations MUST NOT present ceiling verification as spend
        enforcement. A chain that verifies establishes that no hop authorized
        more than it held. It does not establish that the authorized amount
        remains available.</t>
      </section>
    </section>

    <section anchor="verification-algorithm">
      <name>Verification Algorithm</name>
      <t>This section is normative. A verifier presented with an AIP token
      MUST perform steps V1 through V7 before treating any identity or
      capability asserted by the token as established. V1 MUST complete
      before any other step reads link content. The remaining steps MAY be
      performed in any order or interleaved, and when a chain fails more
      than one step, which of the applicable error codes is returned is not
      specified.</t>

      <t>A request that carries no token fails with
      <tt>aip_token_missing</tt>. A token that cannot be parsed in its
      encoding, or whose links do not have the fields required by
      <xref target="links"/>, fails with <tt>aip_token_malformed</tt>.</t>

      <section anchor="v1-chain-integrity">
        <name>Step V1: Chain Integrity</name>
        <t>The verifier MUST verify the signature on every link, as defined
        by the encoding (<xref target="jwt-v1"/> and
        <xref target="biscuit-verification"/>), starting from the root
        public key. Verifying the signature on the presented leaf alone is
        not sufficient.</t>
        <t>Verification MUST be performed against the serialized form as
        received. An implementation that holds a token in a parsed in-memory
        representation MUST re-serialize and re-verify before relying on it,
        rather than trusting the state of its own parsed object.</t>
        <t>A verifier MUST NOT accept any field from a link that it has not
        verified as part of a chain rooted at the issuer's key. Failure
        returns <tt>aip_signature_invalid</tt>.</t>
      </section>

      <section anchor="v2-root-binding">
        <name>Step V2: Root Binding</name>
        <t>The verifier MUST take the issuer of L0 and confirm that the root
        public key used in V1 is the key bound to that identifier:</t>
        <ul>
          <li>For <tt>aip:web:</tt> identifiers, by resolving the identity
          document as specified in <xref target="identity-document"/> and
          comparing the published key.</li>
          <li>For <tt>aip:key:</tt> identifiers, by decoding the key from the
          identifier itself and comparing.</li>
          <li>In the workload-attested anchor mode
          (<xref target="anchor-modes"/>), by the attestation the verifier
          recognises.</li>
        </ul>
        <t>An identifier that does not resolve, or that resolves to a
        different key, returns <tt>aip_identity_unresolvable</tt>. A verifier
        MUST NOT infer the root key from the token.</t>
        <t>V2 establishes which key speaks for the issuer. It does not
        establish that the issuer is entitled to grant authority over the
        relying party's resources: anyone can create an <tt>aip:key:</tt>
        identifier and sign a chain under it. A relying party MUST accept
        chains only from issuers it has chosen, by its own policy, to trust
        as sources of authority for the resource, and MUST reject chains
        from any other issuer. When the relying party holds a fixed set of
        trusted issuer keys this is detected in V1 and returns
        <tt>aip_signature_invalid</tt>; otherwise it returns
        <tt>aip_identity_unresolvable</tt>.</t>
      </section>

      <section anchor="v3-depth">
        <name>Step V3: Depth</name>
        <t>The verifier MUST confirm that L0 declares a max_depth of 0 or
        more and that N, the number of delegation links, does not exceed it.
        A missing max_depth returns <tt>aip_token_malformed</tt>. N greater
        than max_depth returns <tt>aip_depth_exceeded</tt>.</t>
      </section>

      <section anchor="v4-attenuation-walk">
        <name>Step V4: Structural Attenuation Walk</name>
        <t>The verifier MUST confirm that L0 declares tools and expiry, that
        no tools or domains list in any link is empty, and that no
        delegation link declares max_depth. Failure returns
        <tt>aip_token_malformed</tt>.</t>
        <t>The verifier MUST then check L0 and walk the chain from L1 to LN,
        comparing each declared value with the effective value of the
        parent link (<xref target="inheritance"/>):</t>
        <ul>
          <li>Tools: every entry declared by Li MUST be covered
          (<xref target="matching"/>) by some entry of the effective tools
          at L(i-1). Failure returns <tt>aip_scope_insufficient</tt>.</li>
          <li>Domains: if the effective domains at L(i-1) is defined, every
          domain declared by Li MUST be a member of it. If no ancestor
          declares domains, Li MAY declare any non-empty list. Failure
          returns <tt>aip_scope_insufficient</tt>.</li>
          <li>Budget: every declared budget_ceiling, including that of L0,
          MUST be non-negative, and a ceiling declared by Li MUST NOT exceed
          the effective ceiling at L(i-1). Failure returns
          <tt>aip_budget_exceeded</tt>.</li>
          <li>Time: the expiry of L0 MUST NOT be earlier than the current
          time. An expiry declared by Li MUST NOT be later than the effective
          expiry at L(i-1) and MUST NOT be earlier than the current time.
          All of these failures return <tt>aip_token_expired</tt>.</li>
          <li>Principal: if a link declares a principal and an earlier link
          has already declared one, the two MUST be identical. The
          on-behalf-of principal is invariant along a chain: intermediaries
          narrow authority, they do not substitute the party on whose behalf
          the chain acts. Failure returns <tt>aip_token_malformed</tt>.</li>
        </ul>
        <t>This step is REQUIRED and is not satisfied by the container
        format. Signature chaining establishes that links were appended in
        order by successive keyholders. It prevents a link from being
        substituted, reordered, or forged, but it does not establish that
        the capabilities asserted in Li are a subset of those held at
        L(i-1). V4 is a comparison of declared values and MUST NOT be
        replaced by evaluation of the token's policy language.</t>
      </section>

      <section anchor="v5-context">
        <name>Step V5: Delegation Context</name>
        <t>Every delegation link MUST carry a context that is non-empty and
        not only whitespace. A verifier MUST reject a chain in which any
        delegation link omits it or supplies an empty value, returning
        <tt>aip_token_malformed</tt>.</t>
      </section>

      <section anchor="v6-policy">
        <name>Step V6: Request Authorization</name>
        <t>V6 decides whether the specific request falls within the
        authority at the leaf. It has a structural part, which applies to
        both encodings, and a policy part, which applies to the Biscuit
        encoding only.</t>
        <t>Structural part: the requested tool MUST be covered by the
        effective tools at LN. If the request names a domain and the
        effective domains at LN is defined, the domain MUST be a member of
        it. A request that names no domain is not constrained by the
        domains dimension; a relying party that needs domain enforcement
        MUST supply the domain of every request. Failure returns
        <tt>aip_scope_insufficient</tt>.</t>
        <t>Policy part (Biscuit encoding): the verifier MUST evaluate the
        token's Datalog with the ambient facts <tt>tool</tt>,
        <tt>time</tt>, and <tt>depth</tt> bound to the request under
        consideration, and MUST require that every check in every block
        passes. The verifier MUST NOT introduce ambient facts beyond those
        named. In particular it MUST NOT supply a <tt>budget</tt> fact:
        doing so causes any budget check in the chain to evaluate against
        verifier-chosen data rather than against the token. Budget is
        handled in V4. Failure returns <tt>aip_scope_insufficient</tt>.</t>
        <t>Some requests name no tool, for example an MCP
        <tt>initialize</tt> or <tt>tools/list</tt>. For those, a verifier
        MUST still perform V1 through V5 and V7, and skips V6.</t>
      </section>

      <section anchor="v7-revocation">
        <name>Step V7: Revocation with Bounded Staleness</name>
        <t>If the issuer's identity document advertises a revocation endpoint,
        the verifier MUST check whether any key in the chain has been revoked.
        Revocation data MAY be cached. A verifier MUST be configurable with a
        maximum acceptable staleness for cached revocation data, and MUST fail
        closed when its cached data is older than that bound, returning
        <tt>aip_key_revoked</tt> rather than proceeding on stale information.</t>
        <t>Revocation responses MUST be signed by the issuer so that their
        authenticity is verifiable without a trusted transport to the
        revocation endpoint.</t>
        <t>This revision does not specify the format of the revocation
        endpoint, its responses, how revoked keys are identified, or how
        freshness is represented, so V7 cannot yet be implemented
        interoperably. No known implementation performs it
        (<xref target="implementation-status"/>).</t>
      </section>

      <section anchor="v8-result">
        <name>Verification Result</name>
        <t>A token that passes V1 through V7 establishes: the identity of the
        issuer, the capabilities available at the leaf, and that no hop in
        the chain exceeded the authority of its predecessor.</t>
        <t>Whether it also establishes the identity of each delegator and
        delegate depends on the encoding. In the JWT chain encoding each
        delegation link is signed by the key that the previous link named
        in <tt>cnf</tt>, so the chain of keys is authenticated. The pairing
        of that key with the identifier in <tt>sub</tt> is asserted by the
        signer of the previous link. Delegator and delegate identity are
        therefore established only if the verifier also confirms, for each
        link, that the <tt>cnf</tt> key is bound to the <tt>sub</tt>
        identifier, by decoding an <tt>aip:key:</tt> identifier or by
        resolving the identity document of an <tt>aip:web:</tt>
        identifier. A verifier that relies on delegator identity MUST
        perform that check. In the Biscuit encoding delegation blocks are
        appended under keys the token itself supplies, so delegator and
        delegate are asserted by whoever appended the block, not
        authenticated (<xref target="biscuit-identity"/>).</t>
        <t>In neither encoding does verification establish that the
        presenting party is the party the leaf was issued to. See
        <xref target="proof-of-possession"/> and
        <xref target="truncation"/>.</t>
      </section>
    </section>

    <section anchor="encodings">
      <name>Encodings</name>
      <t>This section defines two encodings of the model in
      <xref target="chain-model"/>. Both carry the same fields and are
      verified by the same steps V2 through V7. They differ in V1, in
      resistance to truncation (<xref target="truncation"/>), and in what
      they say about delegators: the JWT chain encoding authenticates the
      chain of holder keys, and delegator identity additionally requires
      the key-to-identifier check of <xref target="v8-result"/>; the
      Biscuit encoding authenticates neither.</t>

      <section anchor="jwt-chain">
        <name>JWT Chain Encoding</name>

        <section anchor="jwt-wire">
          <name>Wire Format</name>
          <t>A JWT chain is the links in order, each a JWS Compact
          Serialization <xref target="RFC7515"/> of a JWT
          <xref target="RFC7519"/>, joined by the tilde character:</t>
          <artwork><![CDATA[
<link0>~<link1>~...~<linkN>
          ]]></artwork>
          <t>The tilde separator follows SD-JWT <xref target="RFC9901"/>.
          No link may be empty. The media type is
          <tt>application/aip-chain+jwt</tt>
          (<xref target="iana-media-type"/>).</t>
          <t>The protected header of every link MUST contain
          <tt>alg</tt> "EdDSA" and <tt>typ</tt> "aip-link+jwt":</t>
          <artwork><![CDATA[
{"alg":"EdDSA","typ":"aip-link+jwt"}
          ]]></artwork>
          <t>Other header parameters are ignored, except that a
          <tt>crit</tt> parameter naming an extension the verifier does not
          understand causes rejection with <tt>aip_token_malformed</tt>
          (<xref target="RFC7515" section="4.1.11"/>).</t>
          <t>The signature algorithm is Ed25519 <xref target="RFC8032"/>.
          Keys in the <tt>cnf</tt> claim are OKP JSON Web Keys
          <xref target="RFC8037"/> carried as confirmation keys
          <xref target="RFC7800"/>.</t>
        </section>

        <section anchor="jwt-claims">
          <name>Claims</name>
          <t>The authority link L0 carries:</t>
          <ul>
            <li><tt>iss</tt> (REQUIRED): the issuer.</li>
            <li><tt>sub</tt> (REQUIRED): the delegate, the first holder.</li>
            <li><tt>iat</tt> (REQUIRED): issue time.</li>
            <li><tt>exp</tt> (REQUIRED): the expiry.</li>
            <li><tt>jti</tt> (REQUIRED): a unique link identifier.</li>
            <li><tt>aip_tools</tt> (REQUIRED): a non-empty JSON array of
            strings.</li>
            <li><tt>aip_domains</tt> (OPTIONAL): a non-empty JSON array of
            strings.</li>
            <li><tt>aip_budget_cents</tt> (OPTIONAL): a non-negative
            integer.</li>
            <li><tt>aip_max_depth</tt> (REQUIRED): an integer of 0 or
            more.</li>
            <li><tt>aip_principal</tt> (OPTIONAL): a string.</li>
            <li><tt>cnf</tt> (REQUIRED): <tt>{"jwk": &lt;key&gt;}</tt>, the
            holder key of <tt>sub</tt>.</li>
            <li><tt>aip_anchor</tt> (OPTIONAL): see
            <xref target="jwt-anchor"/>.</li>
          </ul>
          <t>A delegation link Li carries:</t>
          <ul>
            <li><tt>iss</tt> (REQUIRED): MUST equal the <tt>sub</tt> of
            L(i-1).</li>
            <li><tt>sub</tt> (REQUIRED): the delegate.</li>
            <li><tt>iat</tt> and <tt>jti</tt> (REQUIRED).</li>
            <li><tt>exp</tt> (OPTIONAL): if absent, the link inherits.</li>
            <li><tt>prev</tt> (REQUIRED): the base64url encoding, without
            padding, of the SHA-256 digest of the ASCII JWS Compact
            Serialization of L(i-1) exactly as transmitted.</li>
            <li><tt>aip_ctx</tt> (REQUIRED): the context, a non-empty
            string.</li>
            <li><tt>cnf</tt> (REQUIRED): the holder key of <tt>sub</tt>.</li>
            <li><tt>aip_tools</tt>, <tt>aip_domains</tt>,
            <tt>aip_budget_cents</tt>, <tt>aip_principal</tt>
            (OPTIONAL), as in L0.</li>
          </ul>
          <t>A delegation link MUST NOT carry <tt>aip_max_depth</tt>.</t>
          <t>The <tt>cnf</tt> key MUST be an OKP key with <tt>crv</tt>
          "Ed25519" whose <tt>x</tt> member decodes to 32 bytes.
          <tt>x</tt> MUST be base64url without padding, using only the
          URL-safe alphabet of <xref target="RFC4648" section="5"/>, and
          verifiers MUST reject any other character. A <tt>cnf</tt> that
          does not meet these rules returns <tt>aip_token_malformed</tt>.</t>
          <t>Claim names other than the registered JWT claims are prefixed
          with <tt>aip_</tt> so that they do not collide with registered
          claims of different syntax, such as the space-delimited
          <tt>scope</tt> string of <xref target="RFC9068"/>. The
          <tt>iat</tt> and <tt>jti</tt> claims are for audit and
          correlation; this document defines no verifier processing for
          them.</t>
        </section>

        <section anchor="jwt-v1">
          <name>V1 for the JWT Chain Encoding</name>
          <t>Given a chain and the root public key, a verifier:</t>
          <ol>
            <li>Splits the chain on "~". An empty link returns
            <tt>aip_token_malformed</tt>.</li>
            <li>For each link, checks that the protected header has
            <tt>alg</tt> equal to "EdDSA" and <tt>typ</tt> equal to
            "aip-link+jwt". Any other value, including <tt>alg</tt> "none",
            returns <tt>aip_signature_invalid</tt>.</li>
            <li>Verifies the signature on L0 with the root public key.</li>
            <li>For each i of 1 or more: checks that <tt>prev</tt> equals
            the digest of L(i-1) as received, that <tt>iss</tt> equals the
            <tt>sub</tt> of L(i-1), and verifies the signature on Li with
            the key in the <tt>cnf</tt> of L(i-1). Any mismatch returns
            <tt>aip_signature_invalid</tt>.</li>
          </ol>
          <t>The root public key is a 32-byte Ed25519 key, obtained as in
          V2. Expiry is not checked in V1; it is checked in V4 so that
          every expiry failure returns <tt>aip_token_expired</tt>.</t>
        </section>

        <section anchor="jwt-single-link">
          <name>Single-Link Chains and the Draft-01 Compact Form</name>
          <t>A chain with N equal to 0 is a single JWT. It replaces the
          compact mode of draft-prakash-aip-01, which is no longer a
          separate format.</t>
          <t>For this revision only, verifiers MAY accept a single token
          with header <tt>typ</tt> "aip+jwt" and the draft-01 claims
          (<tt>scope</tt>, <tt>budget_usd</tt>, <tt>max_depth</tt>) as a
          one-link chain. A verifier that does so maps <tt>scope</tt> to
          tools, <tt>budget_usd</tt> to budget_ceiling in cents, and
          <tt>max_depth</tt> to max_depth, and then applies V2 through V7.
          Such a token has no <tt>cnf</tt>, so it is a bearer credential
          and cannot be used to prove possession. This form is deprecated
          and is expected to be removed in a later revision.</t>
        </section>

        <section anchor="jwt-anchor">
          <name>Anchoring to an AIMS Token</name>
          <t>L0 MAY carry an <tt>aip_anchor</tt> claim that binds the chain
          to an OAuth access token or transaction token issued within an
          AIMS deployment (<xref target="aims-relationship"/>). Its value is
          a JSON object with an <tt>alg</tt> member, which MUST be "S256",
          and exactly one of <tt>access_token</tt> or <tt>txn_token</tt>,
          whose value is the base64url encoding, without padding, of the
          SHA-256 digest of the anchored token as transmitted.</t>
          <t>The anchor conveys assurance only to a relying party that holds
          the anchored token and checks the digest. This document does not
          require verifiers to check it, and a chain whose anchor is not
          checked is verified exactly as one without an anchor.</t>
        </section>
      </section>

      <section anchor="biscuit-encoding">
        <name>Biscuit Encoding</name>
        <t>The Biscuit encoding uses Biscuit tokens
        <xref target="BISCUIT"/> with append-only blocks and Datalog policy.
        Block 0 is L0 and is signed by the root key. Block i is Li.</t>

        <section anchor="policy-profiles">
          <name>Policy Profiles</name>
          <t>Three policy profiles of increasing expressiveness are
          defined:</t>
          <ul>
            <li>Simple: templated rules requiring no Datalog knowledge. The
            library generates the canonical forms of
            <xref target="canonical-encoding"/>.</li>
            <li>Standard: a curated Datalog subset without recursion and
            with bounded evaluation.</li>
            <li>Advanced: full Datalog with a maximum of 1000 iterations.
            Opt-in only.</li>
          </ul>
          <t>Checks added under the Standard and Advanced profiles are
          evaluated in the policy part of V6. They do not change the
          structural fields of <xref target="links"/>, which are always
          read from the canonical forms.</t>
        </section>

        <section anchor="canonical-encoding">
          <name>Canonical Block Encoding</name>
          <t>Interoperability of the Biscuit encoding depends on every
          implementation emitting the same Datalog for the same
          authorization intent. Implementations MUST emit exactly the forms
          below. The order of facts and checks within a block is not
          significant.</t>

          <t>The authority block (block 0) MUST contain:</t>
          <sourcecode type="datalog"><![CDATA[
identity("<aip-identifier>");
principal("<identifier>");        ; OPTIONAL, on-behalf-of party
right("<tool>");                  ; one fact per tools entry
domain("<domain>");               ; OPTIONAL, one fact per domain
max_depth(<n>);
budget_ceiling(<cents>);          ; OPTIONAL, integer cents
check if <tool-constraint>;
check if time($t), $t <= <expiry>;
]]></sourcecode>

          <t>Each delegation block (blocks 1 through N) MUST contain:</t>
          <sourcecode type="datalog"><![CDATA[
delegator("<aip-identifier>");
delegate("<aip-identifier>");
context("<non-empty string>");
domain("<domain>");               ; OPTIONAL, one fact per domain
principal("<identifier>");        ; OPTIONAL
budget_ceiling(<cents>);          ; OPTIONAL, integer cents
check if <tool-constraint>;       ; OPTIONAL, absent = inherit
check if time($t), $t <= <expiry>;  ; OPTIONAL, absent = inherit
]]></sourcecode>

          <t>The <tt>&lt;tool-constraint&gt;</tt> is a single check built
          from the block's tools list. Exact names form one clause
          <tt>tool($t), ["&lt;name&gt;", ...].contains($t)</tt>. Each entry
          "&lt;prefix&gt;*" forms a clause
          <tt>tool($t), $t.starts_with("&lt;prefix&gt;")</tt>, and the
          entry "*" forms the clause <tt>tool($t)</tt>. The clauses are
          joined with <tt>or</tt>. <tt>&lt;expiry&gt;</tt> is a UTC
          timestamp of the form YYYY-MM-DDTHH:MM:SSZ.</t>

          <t>Mapping to the model: issuer is the <tt>identity</tt> fact in
          block 0 and the <tt>delegator</tt> fact in later blocks; delegate
          is the <tt>delegate</tt> fact; tools are read from the tool check,
          not from the <tt>right</tt> facts, which are descriptive; domains
          are the <tt>domain</tt> facts; expiry is read from the time check;
          the remaining fields are the facts of the same name.</t>

          <t>Block 0 MUST carry an <tt>identity</tt> fact, and every
          delegation block MUST carry a <tt>delegator</tt> and a
          <tt>delegate</tt> fact. Verifiers MUST reject a block missing one
          of them with <tt>aip_token_malformed</tt>.</t>

          <t>A block MUST NOT carry more than one fact of any of the names
          <tt>identity</tt>, <tt>principal</tt>, <tt>context</tt>,
          <tt>delegator</tt>, <tt>delegate</tt>, <tt>budget_ceiling</tt>,
          and <tt>max_depth</tt>. Verifiers MUST reject such a block with
          <tt>aip_token_malformed</tt>, because a repeated single-valued
          fact makes the block's declared value ambiguous. A delegation
          block MUST NOT carry <tt>max_depth</tt>.</t>

          <t>Scope narrowing is reinforced by conjunction: every block's tool
          check must pass, so the set of tools the Datalog authorizes is the
          intersection of the per-block allowlists. V4 still checks it
          structurally, so that a widening block is reported as malformed
          authority rather than silently authorizing nothing.</t>

          <t>Domains are carried as facts only, never as a Datalog check. A
          check over a <tt>domain</tt> ambient fact would fail every
          request that names no domain, and adding <tt>domain</tt> to the
          ambient facts would let the verifier choose the value being
          checked. Domain attenuation is verified in V4 and the request's
          domain in the structural part of V6.</t>

          <t>Budget is carried as a fact rather than a check. A Datalog check
          of the form <tt>check if budget($b), $b &lt;= N</tt> binds to
          whatever budget facts are in scope during evaluation, which is not
          the same question as whether this block's ceiling narrows its
          parent's. Encoding budget as a check therefore either rejects
          valid chains or, if the verifier supplies a satisfying ambient
          fact, passes unconditionally. Implementations MUST NOT emit a
          <tt>check</tt> statement over <tt>budget</tt>, and verifiers MUST
          NOT inject an ambient <tt>budget</tt> fact.</t>

          <t>In this encoding an empty allowlist has no representation: a
          block with no tool check, or with no <tt>domain</tt> facts,
          inherits. The authority block MUST carry a tool check, and a
          verifier MUST reject an authority block without one with
          <tt>aip_token_malformed</tt>.</t>
        </section>

        <section anchor="biscuit-verification">
          <name>V1 for the Biscuit Encoding</name>
          <t>V1 is Biscuit signature verification of every block from the
          serialized token against the root public key. The verifier then
          reads the fields of each block as described in
          <xref target="canonical-encoding"/>.</t>
        </section>

        <section anchor="biscuit-identity">
          <name>Delegator Identity</name>
          <t>Biscuit appends each block under an ephemeral key carried in
          the token. The signature chain proves the blocks were appended in
          order by successive holders of the token, but it does not prove
          that the party named in <tt>delegator</tt> wrote the block. In
          this encoding delegator and delegate are asserted, not
          authenticated. The issuer of L0 is authenticated by the root key
          and V2.</t>
          <t>Biscuit third-party blocks, which are signed by a key outside
          the token, could let a delegator sign its own block, and a future
          revision MAY specify their use. The reference implementation does
          not use them.</t>
        </section>
      </section>

      <section anchor="encoding-detection">
        <name>Distinguishing the Encodings</name>
        <t>A JWS Compact Serialization starts with the base64url encoding
        of a JSON object, so a JWT chain starts with "eyJ". A verifier
        receiving a token in a binding that does not label its type
        treats a token that starts with "eyJ" as a JWT chain, and a token
        that is a single JWS with header <tt>typ</tt> "aip+jwt" as the
        deprecated draft-01 form (<xref target="jwt-single-link"/>). Any
        other token is parsed as Biscuit. The header is read without
        verification only to choose the verifier; nothing in it is trusted
        before V1.</t>
      </section>
    </section>

    <section anchor="trust-anchors">
      <name>Trust Anchors and Workload Identity</name>
      <t>AIP answers a different question from a workload identity system,
      and a deployment can use both.</t>

      <t>A workload identity system such as SPIFFE
      <xref target="SPIFFE"/>, in the architecture described by
      <xref target="I-D.ietf-wimse-arch"/>, answers "which workload is
      this?" It attests a running process against the platform it runs on
      and issues a credential that says so. Its trust boundary is the
      trust domain it administers, and it does not model authority passing
      between parties.</t>

      <t>AIP answers "on whose authority is this being done, how far back,
      and can a party with no relationship to the origin verify it?" It
      carries delegation across hops and organizations, and it does not by
      itself establish that the process presenting the token is the one
      the platform attested.</t>

      <section anchor="anchor-modes">
        <name>Anchor Modes</name>
        <t>L0 is signed by the issuer's key. Four ways of establishing
        trust in that key, or in the authority behind it, are defined:</t>
        <ul>
          <li>DNS-anchored: the issuer is an <tt>aip:web:</tt> identifier and
          the key is published in an identity document resolved over HTTPS.
          Trust derives from the Web PKI and DNS control.</li>
          <li>Self-certifying: the issuer is an <tt>aip:key:</tt> identifier
          and the key is the identifier. Trust derives from whoever accepted
          the identifier.</li>
          <li>Workload-attested: the issuer's key is bound to a workload
          identity credential issued by an external authority, and the
          identity document records that binding. Trust derives from that
          authority's attestation.</li>
          <li>AIMS-anchored: in the JWT chain encoding, L0 carries an
          <tt>aip_anchor</tt> claim (<xref target="jwt-anchor"/>) binding
          the chain to an access token or transaction token. This
          supplements one of the other modes; it does not replace V2.</li>
        </ul>

        <t>In workload-attested mode, an identity document MAY carry a
        <tt>workload_identity</tt> member naming the credential that attests
        the issuer key, for example a SPIFFE ID. A verifier that recognises
        the naming authority MAY treat that attestation as the basis for
        accepting the root key, in place of resolving the document over
        HTTPS. A verifier that does not recognise it MUST fall back to the
        DNS-anchored or self-certifying path, and MUST NOT treat an
        unrecognised attestation as an endorsement.</t>

        <t>In this deployment a workload
        identity system establishes that the orchestrator is what it claims
        to be inside its own trust domain, and AIP carries what that
        orchestrator was permitted to delegate onward, across boundaries the
        workload identity system does not span.</t>
      </section>
    </section>

    <section anchor="aims-relationship">
      <name>Relationship to AIMS</name>
      <t>AIMS <xref target="I-D.ietf-wimse-aims"/> describes how existing
      standards apply to agent identity and authorization. This section
      states how AIP is intended to fit alongside it. Section numbers refer
      to draft-ietf-wimse-aims-00.</t>
      <ol>
        <li>Identity. AIMS identifies an agent by a WIMSE identifier
        (AIMS Section 6) and gives it credentials (AIMS Section 7). AIP does
        not redefine either. An AIP identifier can be bound to the agent's
        WIMSE identifier through the workload-attested anchor mode
        (<xref target="anchor-modes"/>).</li>
        <li>Anchoring. L0 can be bound to an access token or transaction
        token that an AIMS deployment issued, through
        <tt>aip_anchor</tt> in the JWT chain encoding or through the
        workload-attested anchor in either encoding.</li>
        <li>Division of labor. In the flows of AIMS Sections 10.4 through
        10.6, narrowing is done by an authorization server or a transaction
        token service, which evaluates its policy and issues a new token,
        through token exchange <xref target="RFC8693"/>, transaction tokens
        <xref target="I-D.ietf-oauth-transaction-tokens"/>, or identity and
        authorization chaining across domains
        <xref target="I-D.ietf-oauth-identity-chaining"/>. A transaction token, once
        issued, is propagated along an internal call chain. AIMS Section 10.4.3 covers an agent invoked by another
        agent, with the caller obtaining an access token by an appropriate
        mechanism. AIP covers the hops where no authorization server
        participates in narrowing, for example an agent subdelegating part of
        its own authority to a subagent, or delegating to an agent in another
        organization whose authorization server has no prior trust
        arrangement with the delegator's. On those hops AIP lets the relying
        party verify attenuation from the token itself.</li>
        <li>Policy. AIMS Section 12 places the policy model and document
        format outside its stated scope. The structural constraints of
        <xref target="chain-model"/> are one concrete option for the
        delegation part of such a policy. They are not proposed as an AIMS
        requirement.</li>
        <li>Proof of possession. AIMS Section 9.2 describes application
        layer authentication with WIMSE Workload Proof Tokens and HTTP
        Message Signatures. AIP relies on those mechanisms rather than
        defining its own (<xref target="proof-of-possession"/>).</li>
      </ol>
    </section>

    <section anchor="proof-of-possession">
      <name>Proof of Possession</name>
      <t>Verification establishes what authority a chain conveys and that
      no hop exceeded its predecessor. It does not establish that the party
      presenting the chain is the party the leaf was delegated to.</t>
      <t>In the JWT chain encoding the <tt>cnf</tt> claim of the leaf link
      names the key of the leaf delegate. A presenter can prove possession
      of that key at the message layer, for example by signing the request
      with HTTP Message Signatures <xref target="RFC9421"/>, or with a
      WIMSE Workload Proof Token <xref target="I-D.ietf-wimse-wpt"/> where
      the leaf key is the key of the presenter's workload credential.
      Specifying that binding, including which request components are
      signed and how freshness and replay are handled, is out of scope for
      this document and is left to those mechanisms. A signed request
      without freshness and replay controls can itself be replayed.</t>
      <t>A relying party that relies on attenuation holding against
      downstream holders of a JWT chain MUST verify proof of possession of
      the key named in the leaf link's <tt>cnf</tt>. Without it, a JWT chain
      conveys no more assurance than a bearer grant from its root, for the
      reason given in <xref target="truncation"/>.</t>
      <t>The Biscuit encoding names no holder key and remains a bearer
      credential. Deployments that need proof of possession with it MUST
      bind the token to a key at the transport or message layer, for
      example with mutual TLS or the mechanisms above.</t>
      <t>Implementations MUST NOT describe AIP verification as
      authenticating the presenter.</t>
    </section>

    <section anchor="protocol-bindings">
      <name>Protocol Bindings</name>
      <t>The bindings carry either encoding. The verification steps are not
      restated per binding; every binding applies the algorithm of
      <xref target="verification-algorithm"/> unchanged.</t>

      <section anchor="mcp-binding">
        <name>MCP Binding</name>
        <t>AIP tokens are transported in MCP via the X-AIP-Token HTTP
        header:</t>
        <artwork><![CDATA[
X-AIP-Token: <jwt-chain-or-biscuit-token>
        ]]></artwork>
        <t>For tokens exceeding 4KB, token-by-reference is supported:</t>
        <artwork><![CDATA[
X-AIP-Token-Ref: https://issuer/.well-known/aip/tokens/<id>
        ]]></artwork>
        <t>An MCP server extracts the token from the header, or fetches it
        from the reference URL, determines the encoding as in
        <xref target="encoding-detection"/>, and verifies it according to
        <xref target="verification-algorithm"/>. For <tt>tools/call</tt>
        the requested tool is the string "tool:" followed by the tool name
        in the request, so tools entries for MCP are written in that form
        (for example "tool:search" or "tool:*"). On success the
        server injects the verified identity into the request context,
        where the tool implementation MAY use it for authorization
        decisions, logging, or audit.</t>
        <t>Nine error codes are defined with HTTP status mappings: 401 for
        authentication failures (<tt>aip_token_missing</tt>,
        <tt>aip_token_malformed</tt>, <tt>aip_signature_invalid</tt>,
        <tt>aip_identity_unresolvable</tt>, <tt>aip_token_expired</tt>,
        <tt>aip_key_revoked</tt>) and 403 for authorization failures
        (<tt>aip_scope_insufficient</tt>, <tt>aip_budget_exceeded</tt>,
        <tt>aip_depth_exceeded</tt>).</t>
        <t>A server MAY apply local policy after verification, for example
        a lower depth or budget limit than the chain allows. Failures of
        such policy are not part of this specification. The reference
        proxy reports them as <tt>aip_audit_failed</tt> with status
        403.</t>
        <t>Servers declare AIP requirements via the require_aip field
        in their identity document's protocols.mcp configuration.</t>
      </section>

      <section anchor="a2a-binding">
        <name>A2A Binding</name>
        <t>In A2A interactions, AIP tokens are transported in the
        metadata.aip_token field of task submissions. Agent cards are
        extended with an aip_identity object containing the agent's AIP
        identifier and document URL.</t>
        <t>The calling agent appends a delegation link with attenuated
        authority before sending the task. In addition to
        <xref target="verification-algorithm"/>, the receiving agent
        verifies that the chain has at least one delegation link and that
        the delegate of the leaf link is its own AIP identifier. The receiving
        agent determines the requested tool for V6 from the task, for
        example the skill the task asks it to perform.</t>
      </section>

      <section anchor="http-binding">
        <name>HTTP Binding</name>
        <t>For generic HTTP APIs not using MCP or A2A, tokens are
        transported via the Authorization header with the AIP scheme:</t>
        <artwork><![CDATA[
Authorization: AIP <token>
        ]]></artwork>
        <t>The token is sent as is. Both a JWT chain and a Biscuit token in
        its base64url form consist only of characters permitted in the
        token68 syntax of <xref target="RFC9110" section="11.2"/>.
        Token-by-reference uses the X-AIP-Token-Ref header with a
        5-second fetch timeout and SSRF protection (reject reference URLs
        outside expected domain patterns).</t>
      </section>
    </section>

    <section anchor="delegation-lifecycle">
      <name>Delegation Lifecycle</name>

      <section anchor="bounded-depth">
        <name>Bounded Depth</name>
        <t>L0 declares max_depth, which is REQUIRED. Each delegation link
        increments the depth by 1. A holder whose link is at depth equal to
        max_depth MUST NOT delegate further. A max_depth of 0 means the
        first holder MUST NOT delegate.</t>
      </section>

      <section anchor="delegation-context">
        <name>Delegation Context</name>
        <t>Each delegation link MUST include a non-empty context containing
        a human-readable description of the delegation purpose. Verifiers
        MUST reject tokens with missing or empty context (V5). This keeps
        the reason for each hop in the audit record.</t>
      </section>

      <section anchor="ephemeral-agents">
        <name>Ephemeral Agent Grants</name>
        <t>For short-lived sub-agents, a parent agent generates an Ed25519
        keypair, creates an aip:key: identifier, and appends a delegation
        link with scoped capabilities and a short TTL (5 minutes
        RECOMMENDED). In the JWT chain encoding the new key is the
        <tt>cnf</tt> of that link. The parent's identity document MAY set
        delegation.allow_ephemeral_grants to false to prevent this.</t>
      </section>

      <section anchor="key-rotation">
        <name>Key Rotation</name>
        <t>DNS-based identifiers support zero-downtime key rotation through
        overlapping validity windows on public keys. A new key is published
        with a future valid_from timestamp. Both keys are valid during the
        overlap period. Recommended rotation period is 90 days. Cache TTL
        MUST NOT exceed 5 minutes.</t>
        <t>Self-certifying identifiers cannot rotate keys; key rotation
        requires identity replacement, which is acceptable for ephemeral
        agents.</t>
      </section>

      <section anchor="revocation">
        <name>Revocation</name>
        <t>AIP prefers short-lived tokens over revocation infrastructure.
        Single-link chains SHOULD have a lifetime under 1 hour, which bounds
        the window in which a compromised key or captured token can be
        used; whether that window is acceptable is a deployment decision.
        Key revocation (removing a key
        from the identity document) invalidates all chains rooted in that
        key. Step V7 defines the requirements on revocation checking.
        Token-specific revocation lists are not specified.</t>
      </section>

      <section anchor="future-work">
        <name>Future Work</name>
        <t>Signed records of the outcome of a delegated action, appended
        by the executing agent, are a possible extension. Draft-01 defined
        completion blocks for this purpose; they were never implemented and
        are removed from this revision.</t>
      </section>
    </section>

    <section anchor="implementation-status">
      <name>Implementation Status</name>
      <t>[Note to RFC Editor: please remove this section and the reference
      to RFC 7942 before publication.]</t>
      <t>This section records the status of known implementations of the
      protocol defined by this specification at the time of posting of
      this Internet-Draft, and is based on a proposal described in
      <xref target="RFC7942"/>. The description of implementations in this
      section is intended to assist the IETF in its decision processes in
      progressing drafts to RFCs. Please note that the listing of any
      individual implementation here does not imply endorsement by the
      IETF. Furthermore, no effort has been spent to verify the
      information presented here that was supplied by IETF contributors.
      This is not intended as, and must not be construed to be, a catalog
      of available implementations or their features. Readers are advised
      to note that other implementations may exist.</t>
      <t>According to RFC 7942, "this will allow reviewers and working
      groups to assign due consideration to documents that have the
      benefit of running code, which may serve as evidence of valuable
      experimentation and feedback that have made the implemented
      protocols more mature. It is up to the individual working groups to
      use this information as they see fit".</t>

      <t>Two implementations are known, both by the author. Neither
      provides V7 revocation. The author is not aware of independent
      implementations of this revision.</t>

      <section anchor="impl-python">
        <name>Python Reference Implementation</name>
        <dl>
          <dt>Organization:</dt><dd>The author.</dd>
          <dt>Name:</dt><dd>agent-identity-protocol (Python),
          https://github.com/sunilp/aip</dd>
          <dt>Licensing:</dt><dd>Apache-2.0.</dd>
          <dt>Maturity:</dt><dd>Reference implementation. The code
          described here is on a development branch and not yet in a
          released version; the latest release (0.5.0) implements
          draft-01.</dd>
          <dt>Coverage:</dt>
          <dd>
            <t>Both encodings on one link model. V1, V3, V4, V5, and both
            parts of V6, including domains and the rules for empty
            allowlists, repeated single-valued Biscuit facts, and
            <tt>cnf</tt> key syntax, and rejection of Biscuit blocks
            missing <tt>identity</tt>, <tt>delegator</tt>, or
            <tt>delegate</tt>. MCP middleware, an MCP proxy, and an A2A
            verifier that accept either encoding.</t>
            <t>Draft-01 compact tokens: the library verifier for JWT chains
            maps a token with <tt>typ</tt> "aip+jwt" onto the link model as
            in <xref target="jwt-single-link"/>. The MCP middleware and
            proxy do not use that path; for such tokens they keep draft-01
            compact semantics: signature and expiry checks, an exact match
            of the requested tool against <tt>scope</tt> with no wildcards,
            and no V3 or V4. The compact verifier rejects any
            <tt>typ</tt> other than "aip+jwt" as malformed. The A2A verifier
            does not accept compact tokens.</t>
            <t>V2: the library takes the root key from its caller and does
            not resolve identity documents over HTTPS. Only the MCP proxy
            compares the issuer a chain declares with the issuer its key is
            configured for, and only when trusted keys are configured as a
            mapping from issuer to key; with a single unbound key it skips
            the comparison and logs a warning. The MCP middleware and the A2A
            verifier take one key and do not compare issuers.
            The JWT chain verifier does not check that links carry
            <tt>iat</tt> and <tt>jti</tt>, which <xref target="jwt-claims"/>
            requires of issuers. V7 is not implemented. The workload-attested anchor
            mode, the token-by-reference header, and the HTTP
            Authorization binding are not implemented.
            <tt>aip_anchor</tt> is carried but not checked. No binding
            supplies a request domain, so domain constraints are enforced
            in V4 but not against requests. The JWT chain verifier does not
            check that each <tt>cnf</tt> key is bound to its <tt>sub</tt>
            identifier (<xref target="v8-result"/>). The MCP proxy, middleware and A2A
            verifier do not verify proof of possession, so JWT chains presented to
            them are subject to truncation
            (<xref target="truncation"/>).</t>
            <t>Identity document signatures are decoded as base64url
            (standard base64 is also accepted for documents written by
            earlier versions). Canonicalization uses sorted-key compact
            JSON, which agrees with JCS for documents whose strings are
            ASCII and whose numbers are integers. The document is first
            parsed into a fixed model, so members the model does not define
            (including <tt>workload_identity</tt> of
            <xref target="anchor-modes"/>) and members whose value is null
            are dropped from the bytes that are verified. The signature is
            checked against the first listed key only.</t>
          </dd>
          <dt>Testing:</dt><dd><t>At commit 989a4f2, 311 unit and
          integration tests (python -m pytest in the python directory),
          including a suite that runs the same forged-delegation cases
          (tool widening, domain widening, budget increase, principal
          substitution, missing context) through both encodings and
          requires the same error code from each.</t>
          <t>A further 26 cross-language tests between the Python and Rust
          implementations, in three groups: 4 exchange Biscuit chains with
          a delegation block between the implementations, two checking
          acceptance and two checking that a tool removed by delegation is
          rejected; 2 check that draft-01 compact JWTs minted by either
          verify in the other; and 20 check that both render the same
          Datalog for the tool, budget and depth parts of an authority
          block and that neither emits a forbidden budget or depth check.
          Eight of those 20 use an empty tools list, which this revision
          makes malformed. None of them covers the JWT
          chain encoding or domains.</t></dd>
          <dt>Contact:</dt><dd>sunil@sunilprakash.com</dd>
        </dl>
      </section>

      <section anchor="impl-rust">
        <name>Rust Implementation</name>
        <dl>
          <dt>Organization:</dt><dd>The author.</dd>
          <dt>Name:</dt><dd>aip-core, aip-token, and aip-mcp crates, same
          repository.</dd>
          <dt>Licensing:</dt><dd>Apache-2.0.</dd>
          <dt>Coverage:</dt>
          <dd>The Biscuit encoding at the draft-01 level: V1, V3, the
          tools, budget, and principal parts of V4, V5, and the policy part
          of V6, with expiry enforced by the Datalog time check only. It
          interoperates with the Python implementation for tokens without
          domains. It has no JWT chain encoding, no domains, and does not
          reject repeated single-valued facts or max_depth in delegation
          blocks. It mints and accepts an authority block with no tool
          check when given an empty tools list, which imposes no tool
          constraint; this revision makes such a block malformed. It
          verifies principal invariance but cannot mint a
          <tt>principal</tt> fact. It decodes identity document signatures
          as hex, which does not match <xref target="identity-document"/>.
          V7 is not implemented.</dd>
          <dt>Testing:</dt><dd>At commit 989a4f2, 80 tests (cargo test in
          the rust directory).</dd>
          <dt>Contact:</dt><dd>sunil@sunilprakash.com</dd>
        </dl>
      </section>

    </section>

    <section anchor="security-considerations">
      <name>Security Considerations</name>

      <section anchor="threat-model">
        <name>Threat Model</name>
        <t>AIP is designed to resist the following attack categories:</t>
        <ul>
          <li>Scope widening: an agent attempts to exceed its delegated
          capabilities. A link that widens is rejected by the structural
          attenuation walk (V4). In the JWT chain encoding a downstream
          holder can still regain an ancestor's wider authority by
          truncating the chain, unless the relying party verifies proof of
          possession (<xref target="truncation"/>).</li>
          <li>Delegation depth violation: an agent attempts to delegate
          beyond the maximum permitted depth. Prevented by V3.</li>
          <li>Token replay: a captured token is reused. Mitigated by short
          lifetimes, and prevented only where the relying party verifies
          proof of possession (<xref target="proof-of-possession"/>).</li>
          <li>Token forgery: an attacker constructs a token without holding
          the private key. Prevented by Ed25519 signature verification.</li>
          <li>Identity spoofing: an agent claims a false issuer identity.
          Prevented by V2. In the JWT chain encoding the chain of holder
          keys is authenticated, and delegator identity is protected only
          when the verifier also checks each key against its identifier
          (<xref target="v8-result"/>). The Biscuit encoding does not
          protect delegator identity.</li>
          <li>Audit evasion: an agent delegates with empty context to avoid
          audit trails. Prevented by V5.</li>
          <li>Ancestor substitution: an attacker holding a valid leaf
          attempts to present it beneath a different, more permissive
          ancestor. Prevented by V1, which verifies the full signature chain
          from the root key. In the JWT chain encoding each link also
          commits to its parent through <tt>prev</tt>.</li>
        </ul>

        <t>Signature chaining and attenuation checking are different
        properties. Signature chaining (V1) prevents links
        from being forged, reordered, or substituted. Attenuation checking
        (V4) prevents a link from asserting more than its predecessor held.
        The first is a property of the container; the second is a property
        of the capability content. Neither implies the other, and a verifier
        that performs only the first will accept a chain in which a
        delegation widened its own authority. Both are REQUIRED.</t>
      </section>

      <section anchor="truncation">
        <name>Truncation of JWT Chains</name>
        <t>Any prefix L0 through Lk of a valid JWT chain is itself a valid
        chain. It carries the authority held by the delegate of Lk, which
        is wider than or equal to the authority at the leaf. A holder of a
        longer chain can therefore remove its own and later links and
        present the prefix. Signature verification and V4 will both
        succeed.</t>
        <t>Proof of possession closes this: the prefix names the key of an
        earlier holder in its leaf <tt>cnf</tt>, which the truncating
        party does not hold. A relying party that relies on attenuation
        holding against downstream holders MUST verify proof of possession
        of the key named in the leaf link's <tt>cnf</tt>, as stated in
        <xref target="proof-of-possession"/>. Without it, a JWT chain
        conveys no more assurance than a bearer grant from its root.</t>
        <t>The Biscuit encoding resists truncation, because the token
        carries only the private key for its last block, and presenting a
        shorter chain requires the key for an earlier block, which a
        downstream holder does not have. It remains a bearer credential in
        every other respect.</t>
      </section>

      <section anchor="identity-guarantee">
        <name>Identity Guarantees Depend on the Encoding</name>
        <t>In the JWT chain encoding a delegation link can only be produced
        by the holder of the key the previous link named, so the chain of
        keys is authenticated. The identifier paired with each key is the
        previous signer's assertion until the verifier checks the binding
        (<xref target="v8-result"/>). Without that check, a delegator can
        name another party's identifier in <tt>sub</tt> next to its own key
        in <tt>cnf</tt> and sign the next link under that name. In the
        Biscuit encoding any holder can append a block naming any
        delegator. Relying parties and
        auditors MUST NOT treat a Biscuit <tt>delegator</tt> fact as
        evidence that the named party delegated.</t>
      </section>

      <section anchor="datalog-considerations">
        <name>Datalog Encoding</name>
        <ul>
          <li>Named rules shared between blocks do not attenuate. Datalog
          takes the union of rules with the same head, so a delegation
          block's narrower rule is added to the ancestor's broader rule
          rather than replacing it, and the broader rule then satisfies the
          delegation block's check. Each block's tool constraint MUST be one
          self-contained check, as in
          <xref target="canonical-encoding"/>.</li>
          <li>Budget MUST be a structural fact, not a check, and verifiers
          MUST NOT inject ambient budget facts
          (<xref target="canonical-encoding"/>).</li>
          <li>Block and authorizer sources are Datalog text. A string value
          containing a double quote, a backslash, or a control character
          can close its own term and append facts, checks, or policies,
          either to a signed block or to the authorizer that decides a
          request. Implementations MUST reject such values in identifiers,
          tools, domains, and context before they become Datalog, and MUST
          bind the requested tool in V6 as a parameter or validate it the
          same way. Earlier versions of the reference implementation had
          authorization bypasses of this kind.</li>
        </ul>
      </section>

      <section anchor="conformance-note">
        <name>Agreement Is Not Conformance</name>
        <t>Two implementations that accept each other's tokens can both be
        wrong in the same way. During the development of draft-01, the
        Python and Rust implementations passed their cross-language tests
        while both failed to perform checks this document requires.
        Implementers should test against the MUST statements of this
        document, including negative cases, and not only against another
        implementation.</t>
      </section>

      <section anchor="adversarial-evaluation">
        <name>Adversarial Evaluation</name>
        <t>The companion paper <xref target="AIP-PAPER"/> reports an
        evaluation of an earlier version of the reference implementation
        against six attack categories. That evaluation predates this
        revision and the JWT chain encoding, and is not evidence about
        either.</t>
      </section>

      <section anchor="crypto-agility">
        <name>Cryptographic Agility</name>
        <t>This revision mandates Ed25519 exclusively, and the JWT chain
        encoding pins the <tt>alg</tt> header. No algorithm negotiation is
        supported. This is a deliberate choice to eliminate downgrade
        attacks and reduce implementation complexity. Future revisions MAY
        introduce additional algorithms through a new <tt>typ</tt> value
        or the protocol version field.</t>
      </section>

      <section anchor="transport-security">
        <name>Transport Security</name>
        <t>Identity document resolution and token-by-reference fetching
        MUST use HTTPS. Implementations SHOULD enforce TLS 1.3 or later.
        Token-by-reference URLs MUST be validated against expected domain
        patterns to prevent SSRF attacks. Fetch timeout SHOULD be 5
        seconds.</t>
      </section>
    </section>

    <section anchor="privacy-considerations">
      <name>Privacy Considerations</name>
      <t>Every holder of a chain, and every relying party it is presented
      to, can read all of its links. The context of each delegation link,
      the principal, the identifiers of every participant, and the tools
      and domains granted are therefore disclosed downstream. Delegators
      SHOULD keep context to what an auditor needs to understand the
      purpose of the hop and SHOULD NOT put personal data in it. Relying
      parties that log verified chains SHOULD apply the retention and
      access controls they apply to other authorization records.</t>
    </section>

    <section anchor="iana-considerations">
      <name>IANA Considerations</name>

      <t>This document requests the following IANA registrations:</t>

      <section anchor="iana-auth-scheme">
        <name>HTTP Authentication Scheme</name>
        <t>Registration of the "AIP" HTTP authentication scheme in the
        "HTTP Authentication Schemes" registry:</t>
        <ul>
          <li>Authentication Scheme Name: AIP</li>
          <li>Reference: This document, <xref target="http-binding"/></li>
        </ul>
      </section>

      <section anchor="iana-well-known">
        <name>Well-Known URI</name>
        <t>Registration of the "aip" well-known URI suffix in the
        "Well-Known URIs" registry:</t>
        <ul>
          <li>URI Suffix: aip</li>
          <li>Change Controller: IETF</li>
          <li>Reference: This document, <xref target="identity-document"/></li>
        </ul>
      </section>

      <section anchor="iana-media-type">
        <name>Media Types</name>
        <t>Registration of the following media types in the "Media Types"
        registry, using the template of <xref target="RFC6838"/>. The
        following fields are the same for each:</t>
        <ul>
          <li>Type name: application</li>
          <li>Required parameters: N/A</li>
          <li>Optional parameters: N/A</li>
          <li>Encoding considerations: 7bit; the value consists of ASCII
          characters only</li>
          <li>Security considerations: see
          <xref target="security-considerations"/> of this document</li>
          <li>Interoperability considerations: N/A</li>
          <li>Published specification: this document</li>
          <li>Applications that use this media type: AI agent systems and
          the services they call</li>
          <li>Fragment identifier considerations: N/A</li>
          <li>Additional information: Deprecated alias names for this
          type: N/A; Magic number(s): N/A; File extension(s): N/A;
          Macintosh file type code(s): N/A</li>
          <li>Person and email address to contact for further information:
          Sunil Prakash, sunil@sunilprakash.com</li>
          <li>Intended usage: COMMON, except "aip+jwt", which is
          OBSOLETE</li>
          <li>Restrictions on usage: none</li>
          <li>Author: Sunil Prakash</li>
          <li>Change controller: IETF</li>
        </ul>
        <t>The subtypes are:</t>
        <ul>
          <li>Subtype name "aip-chain+jwt": a JWT chain
          (<xref target="jwt-wire"/>).</li>
          <li>Subtype name "aip-link+jwt": a single link of a JWT chain. The
          JWT <tt>typ</tt> header value "aip-link+jwt" is this media type
          with the "application/" prefix omitted, as described in
          <xref target="RFC7515" section="4.1.9"/>.</li>
          <li>Subtype name "aip+jwt": the draft-01 compact form, deprecated
          (<xref target="jwt-single-link"/>). This registration was
          requested by draft-01 and is kept so that the deprecated
          <tt>typ</tt> value remains defined.</li>
        </ul>
      </section>

      <section anchor="iana-jwt-claims">
        <name>JSON Web Token Claims</name>
        <t>Registration of the following claims in the "JSON Web Token
        Claims" registry established by <xref target="RFC7519"/>. For all
        of them the Change Controller is IETF and the Specification
        Document is <xref target="jwt-claims"/> of this document.</t>
        <table anchor="jwt-claims-table">
          <name>JWT Claims</name>
          <thead>
            <tr><th>Claim Name</th><th>Claim Description</th></tr>
          </thead>
          <tbody>
            <tr><td>prev</td><td>Digest of the previous link in an AIP JWT chain</td></tr>
            <tr><td>aip_tools</td><td>AIP tools allowlist</td></tr>
            <tr><td>aip_domains</td><td>AIP domains allowlist</td></tr>
            <tr><td>aip_budget_cents</td><td>AIP budget ceiling in cents</td></tr>
            <tr><td>aip_max_depth</td><td>AIP maximum delegation depth</td></tr>
            <tr><td>aip_principal</td><td>AIP on-behalf-of principal</td></tr>
            <tr><td>aip_ctx</td><td>AIP delegation context</td></tr>
            <tr><td>aip_anchor</td><td>Digest of an anchoring OAuth token</td></tr>
          </tbody>
        </table>
      </section>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
        </reference>

        <reference anchor="RFC4648" target="https://www.rfc-editor.org/info/rfc4648">
          <front>
            <title>The Base16, Base32, and Base64 Data Encodings</title>
            <author initials="S." surname="Josefsson" fullname="S. Josefsson"/>
            <date year="2006" month="October"/>
          </front>
          <seriesInfo name="RFC" value="4648"/>
        </reference>

        <reference anchor="RFC7515" target="https://www.rfc-editor.org/info/rfc7515">
          <front>
            <title>JSON Web Signature (JWS)</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <author initials="J." surname="Bradley" fullname="J. Bradley"/>
            <author initials="N." surname="Sakimura" fullname="N. Sakimura"/>
            <date year="2015" month="May"/>
          </front>
          <seriesInfo name="RFC" value="7515"/>
        </reference>

        <reference anchor="RFC7519" target="https://www.rfc-editor.org/info/rfc7519">
          <front>
            <title>JSON Web Token (JWT)</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <author initials="J." surname="Bradley" fullname="J. Bradley"/>
            <author initials="N." surname="Sakimura" fullname="N. Sakimura"/>
            <date year="2015" month="May"/>
          </front>
          <seriesInfo name="RFC" value="7519"/>
        </reference>

        <reference anchor="RFC7800" target="https://www.rfc-editor.org/info/rfc7800">
          <front>
            <title>Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs)</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <author initials="J." surname="Bradley" fullname="J. Bradley"/>
            <author initials="H." surname="Tschofenig" fullname="H. Tschofenig"/>
            <date year="2016" month="April"/>
          </front>
          <seriesInfo name="RFC" value="7800"/>
        </reference>

        <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
            <author initials="S." surname="Josefsson" fullname="S. Josefsson"/>
            <author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8032"/>
        </reference>

        <reference anchor="RFC8037" target="https://www.rfc-editor.org/info/rfc8037">
          <front>
            <title>CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE)</title>
            <author initials="I." surname="Liusvaara" fullname="I. Liusvaara"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8037"/>
        </reference>

        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
        </reference>

        <reference anchor="RFC8785" target="https://www.rfc-editor.org/info/rfc8785">
          <front>
            <title>JSON Canonicalization Scheme (JCS)</title>
            <author initials="A." surname="Rundgren" fullname="A. Rundgren"/>
            <author initials="B." surname="Jordan" fullname="B. Jordan"/>
            <author initials="S." surname="Erdtman" fullname="S. Erdtman"/>
            <date year="2020" month="June"/>
          </front>
          <seriesInfo name="RFC" value="8785"/>
        </reference>

        <reference anchor="RFC9110" target="https://www.rfc-editor.org/info/rfc9110">
          <front>
            <title>HTTP Semantics</title>
            <author initials="R." surname="Fielding" fullname="R. Fielding" role="editor"/>
            <author initials="M." surname="Nottingham" fullname="M. Nottingham" role="editor"/>
            <author initials="J." surname="Reschke" fullname="J. Reschke" role="editor"/>
            <date year="2022" month="June"/>
          </front>
          <seriesInfo name="STD" value="97"/>
          <seriesInfo name="RFC" value="9110"/>
        </reference>

        <reference anchor="BISCUIT" target="https://github.com/eclipse-biscuit/biscuit/blob/v3.3/SPECIFICATIONS.md">
          <front>
            <title>Biscuit, a bearer token with offline attenuation and decentralized verification</title>
            <author initials="G." surname="Couprie" fullname="Geoffroy Couprie"/>
            <author>
              <organization>Eclipse Biscuit project</organization>
            </author>
            <date year="2024" month="December"/>
          </front>
          <refcontent>Specification for Biscuit 3.x, tag v3.3</refcontent>
        </reference>
      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942">
          <front>
            <title>Improving Awareness of Running Code: The Implementation Status Section</title>
            <author initials="Y." surname="Sheffer" fullname="Y. Sheffer"/>
            <author initials="A." surname="Farrel" fullname="A. Farrel"/>
            <date year="2016" month="July"/>
          </front>
          <seriesInfo name="BCP" value="205"/>
          <seriesInfo name="RFC" value="7942"/>
        </reference>

        <reference anchor="RFC8067" target="https://www.rfc-editor.org/info/rfc8067">
          <front>
            <title>Updating When Standards Track Documents May Refer Normatively to Documents at a Lower Level</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="BCP" value="97"/>
          <seriesInfo name="RFC" value="8067"/>
        </reference>

        <reference anchor="RFC8693" target="https://www.rfc-editor.org/info/rfc8693">
          <front>
            <title>OAuth 2.0 Token Exchange</title>
            <author initials="M." surname="Jones" fullname="Michael B. Jones"/>
            <author initials="A." surname="Nadalin" fullname="Anthony Nadalin"/>
            <author initials="B." surname="Campbell" fullname="Brian Campbell"/>
            <author initials="J." surname="Bradley" fullname="John Bradley"/>
            <author initials="C." surname="Mortimore" fullname="Chuck Mortimore"/>
            <date year="2020" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8693"/>
        </reference>

        <reference anchor="RFC6838" target="https://www.rfc-editor.org/info/rfc6838">
          <front>
            <title>Media Type Specifications and Registration Procedures</title>
            <author initials="N." surname="Freed" fullname="N. Freed"/>
            <author initials="J." surname="Klensin" fullname="J. Klensin"/>
            <author initials="T." surname="Hansen" fullname="T. Hansen"/>
            <date year="2013" month="January"/>
          </front>
          <seriesInfo name="BCP" value="13"/>
          <seriesInfo name="RFC" value="6838"/>
        </reference>

        <reference anchor="MCP" target="https://modelcontextprotocol.io/specification/2026-07-28">
          <front>
            <title>Model Context Protocol Specification, version 2026-07-28</title>
            <author>
              <organization>Model Context Protocol project</organization>
            </author>
            <date year="2026" month="July" day="28"/>
          </front>
        </reference>

        <reference anchor="A2A" target="https://a2a-protocol.org/v1.0.0/specification/">
          <front>
            <title>Agent2Agent (A2A) Protocol Specification, version 1.0.0</title>
            <author>
              <organization>A2A Project</organization>
            </author>
            <date year="2026" month="March" day="12"/>
          </front>
        </reference>

        <reference anchor="I-D.ietf-oauth-transaction-tokens">
          <front>
            <title>Transaction Tokens</title>
            <author initials="A." surname="Tulshibagwale" fullname="Atul Tulshibagwale"/>
            <author initials="G." surname="Fletcher" fullname="George Fletcher"/>
            <author initials="P." surname="Kasselman" fullname="Pieter Kasselman"/>
            <date year="2026" month="July" day="30"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-oauth-transaction-tokens-11"/>
        </reference>

        <reference anchor="I-D.ietf-oauth-identity-chaining">
          <front>
            <title>OAuth Identity and Authorization Chaining Across Domains</title>
            <author initials="A." surname="Schwenkschuster" fullname="Arndt Schwenkschuster"/>
            <author initials="P." surname="Kasselman" fullname="Pieter Kasselman"/>
            <author initials="K." surname="Burgin" fullname="Kelley Burgin"/>
            <author initials="M." surname="Jenkins" fullname="Michael J. Jenkins"/>
            <author initials="B." surname="Campbell" fullname="Brian Campbell"/>
            <author initials="A." surname="Parecki" fullname="Aaron Parecki"/>
            <date year="2026" month="July" day="19"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-oauth-identity-chaining-17"/>
        </reference>

        <reference anchor="RFC9068" target="https://www.rfc-editor.org/info/rfc9068">
          <front>
            <title>JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens</title>
            <author initials="V." surname="Bertocci" fullname="V. Bertocci"/>
            <date year="2021" month="October"/>
          </front>
          <seriesInfo name="RFC" value="9068"/>
        </reference>

        <reference anchor="RFC9421" target="https://www.rfc-editor.org/info/rfc9421">
          <front>
            <title>HTTP Message Signatures</title>
            <author initials="A." surname="Backman" fullname="A. Backman" role="editor"/>
            <author initials="J." surname="Richer" fullname="J. Richer" role="editor"/>
            <author initials="M." surname="Sporny" fullname="M. Sporny"/>
            <date year="2024" month="February"/>
          </front>
          <seriesInfo name="RFC" value="9421"/>
        </reference>

        <reference anchor="RFC9901" target="https://www.rfc-editor.org/info/rfc9901">
          <front>
            <title>Selective Disclosure for JSON Web Tokens</title>
            <author initials="D." surname="Fett" fullname="D. Fett"/>
            <author initials="K." surname="Yasuda" fullname="K. Yasuda"/>
            <author initials="B." surname="Campbell" fullname="B. Campbell"/>
            <date year="2025" month="November"/>
          </front>
          <seriesInfo name="RFC" value="9901"/>
        </reference>

        <reference anchor="I-D.ietf-wimse-aims">
          <front>
            <title>AI Identity Management System</title>
            <author initials="P." surname="Kasselman" fullname="Pieter Kasselman"/>
            <author initials="J." surname="Lombardo" fullname="Jeff Lombardo"/>
            <author initials="Y." surname="Rosomakho" fullname="Yaroslav Rosomakho"/>
            <author initials="B." surname="Campbell" fullname="Brian Campbell"/>
            <author initials="N." surname="Steele" fullname="Nick Steele"/>
            <author initials="A." surname="Parecki" fullname="Aaron Parecki"/>
            <date year="2026" month="September" day="15"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-wimse-aims-00"/>
        </reference>

        <reference anchor="SPIFFE" target="https://spiffe.io/">
          <front>
            <title>Secure Production Identity Framework for Everyone (SPIFFE)</title>
            <author>
              <organization>Cloud Native Computing Foundation</organization>
            </author>
            <date year="2026"/>
          </front>
        </reference>

        <reference anchor="I-D.ietf-wimse-arch">
          <front>
            <title>Workload Identity in a Multi System Environment (WIMSE) Architecture</title>
            <author initials="J." surname="Salowey" fullname="Joseph A. Salowey"/>
            <author initials="Y." surname="Rosomakho" fullname="Yaroslav Rosomakho"/>
            <author initials="H." surname="Tschofenig" fullname="Hannes Tschofenig"/>
            <date year="2026" month="July" day="6"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-wimse-arch-08"/>
        </reference>

        <reference anchor="I-D.ietf-wimse-wpt">
          <front>
            <title>WIMSE Workload Proof Token</title>
            <author initials="B." surname="Campbell" fullname="Brian Campbell"/>
            <author initials="A." surname="Schwenkschuster" fullname="Arndt Schwenkschuster"/>
            <date year="2026" month="August" day="27"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-wimse-wpt-02"/>
        </reference>

        <reference anchor="I-D.reece-wimse-cross-org-delegation">
          <front>
            <title>Cross-Organizational Delegation for Workload and Agent Identity: Problem Statement and Requirements</title>
            <author initials="M." surname="Reece" fullname="Morgan Reece"/>
            <date year="2026" month="August" day="31"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-reece-wimse-cross-org-delegation-02"/>
        </reference>

        <reference anchor="I-D.rampalli-pedigree">
          <front>
            <title>PEDIGREE: Verifiable Delegation Identity for Agentic AI Systems</title>
            <author initials="K." surname="Rampalli" fullname="Karthik Rampalli"/>
            <date year="2026" month="April" day="24"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-rampalli-pedigree-00"/>
        </reference>

        <reference anchor="AIP-PAPER" target="https://arxiv.org/abs/2603.24775">
          <front>
            <title>AIP: Agent Identity Protocol for Verifiable Delegation Across MCP and A2A</title>
            <author initials="S." surname="Prakash" fullname="Sunil Prakash"/>
            <date year="2026" month="March" day="27"/>
          </front>
        </reference>
      </references>
    </references>

    <section anchor="cross-org-mapping">
      <name>Cross-Organization Delegation Requirements Mapping</name>
      <t><xref target="I-D.reece-wimse-cross-org-delegation"/> enumerates
      requirements for delegation between organizations that share no
      operator, no runtime, and no bilateral agreement. Its -02 revision
      lists ten (R1 through R10); draft-01 of this document mapped the
      nine of its -00 revision. This appendix maps AIP against them.
      Each verdict was checked against the implementations described in
      <xref target="implementation-status"/>, and a verdict distinguishes
      what this document specifies from what is implemented.</t>

      <t>Other proposals address overlapping parts of the same problem,
      including <xref target="I-D.rampalli-pedigree"/>. The requirements
      themselves, rather than any one mechanism, are the useful common
      ground, and several of the gaps identified below are shared across
      proposals.</t>

      <dl>
        <dt>R1, Recursive attenuation: MET in the Biscuit encoding; in the
        JWT chain encoding, MET only where the relying party verifies proof
        of possession.</dt>
        <dd>The attenuation invariant (<xref target="attenuation-invariant"/>)
        and V4 require each hop to be narrower than or equal to its parent
        across tools, domains, budget, expiry, and principal, checked
        structurally from the conveyed authority alone. In the JWT chain
        encoding any prefix of a valid chain also verifies, so a downstream
        holder can present an ancestor's wider authority unless the relying
        party verifies possession of the leaf key (R4,
        <xref target="truncation"/>). No implementation verifies it today.
        The Python implementation performs V4 for both encodings on one
        model, and domains are now encoded in both. The Rust implementation
        does not encode domains.</dd>

        <dt>R2, Cross-organizational verification: MET.</dt>
        <dd>An <tt>aip:web:</tt> issuer publishes its key at a location
        derived from its own DNS name, and a relying party resolves it over
        HTTPS with no prior arrangement. An <tt>aip:key:</tt> issuer needs
        no resolution at all. Neither requires a federation relationship
        established in advance of the interaction. The reference
        implementations take issuer keys from configuration rather than
        resolving documents.</dd>

        <dt>R3, No runtime callback: MET, except V7.</dt>
        <dd>Once the issuer's identity document is held, verification is
        local. Documents are cacheable, so the originating organization is
        not on the critical path. When an issuer advertises a revocation
        endpoint, V7 introduces a cached, bounded-staleness dependency on
        it.</dd>

        <dt>R4, Proof of possession: PARTIAL in the JWT chain encoding; NOT
        MET in the Biscuit encoding.</dt>
        <dd>In the JWT chain encoding the leaf <tt>cnf</tt> names the key a
        presenter must prove, and the proof is delegated to HTTP Message
        Signatures or a WIMSE Workload Proof Token
        (<xref target="proof-of-possession"/>). This document does not
        define a profile of either, and the reference MCP proxy and
        middleware do not verify proof of possession. The Biscuit encoding is a
        bearer credential.</dd>

        <dt>R5, Principal binding and invariance: MET when declared.</dt>
        <dd>A chain MAY declare a principal, and V4 requires that no later
        link declare a different one. A chain that omits the principal
        conveys agent authority only and does not satisfy R5. The Python
        implementation mints and verifies the principal in both encodings.
        The Rust implementation verifies it but cannot mint it.</dd>

        <dt>R6, Dual-axis authorization: NOT MET, and out of scope.</dt>
        <dd>AIP conveys the agent's authority and the identity of the bound
        principal. It does not carry the principal's entitlements, and a
        verifier cannot evaluate them from the token. Composing the two
        axes is the relying party's responsibility.</dd>

        <dt>R7, Authentic, bounded-staleness revocation: NOT MET.</dt>
        <dd>V7 states the requirements: signed revocation responses and a
        configurable maximum staleness with fail-closed behavior. The
        endpoint and response format are not specified, so V7 cannot be
        implemented interoperably, and no implementation performs it. Draft-01 recorded this requirement as met, which was
        not accurate.</dd>

        <dt>R8, Tamper-evident, composable audit: PARTIAL.</dt>
        <dd>In both encodings a link cannot be altered or inserted without
        breaking V1, and every delegation link records its delegator,
        delegate, and context. In the JWT chain encoding V1 does not detect
        the removal of trailing links, because every prefix is a valid
        chain (<xref target="truncation"/>); detecting it requires proof of
        possession. In the JWT chain encoding each
        link is signed by the key its parent designated, and the record is
        attributable to a named participant when the verifier checks the
        key-to-identifier binding (<xref target="v8-result"/>). In the Biscuit
        encoding delegator records are unauthenticated assertions
        (<xref target="biscuit-identity"/>). Recording of outcomes and
        cost was removed with completion blocks.</dd>

        <dt>R9, Format and transport agnosticism: MET.</dt>
        <dd>Both encodings share one link model and one verification
        algorithm, and neither presupposes a transport. Bindings are
        specified for MCP, A2A, and generic HTTP.</dd>

        <dt>R10, Execution-time human authorization: NOT MET.</dt>
        <dd>AIP has no way to mark a class of actions as requiring
        execution-time evidence of a human approval, nor to carry or verify
        such evidence. This requirement was added after draft-01.</dd>
      </dl>

      <t>Summarising the gaps: AIP does not by itself prove possession
      (R4), and in the JWT chain encoding attenuation (R1) and audit
      completeness (R8) depend on that proof. It does not evaluate
      principal entitlements (R6), provide implemented revocation (R7),
      authenticate delegators in the Biscuit encoding or without the
      key-to-identifier check in the JWT chain encoding (R8), or carry
      human approval evidence (R10).</t>
    </section>

    <section anchor="changes-from-01">
      <name>Changes from draft-prakash-aip-01</name>
      <ul>
        <li>Moved to the IETF stream as an individual submission with
        intended status Standards Track.</li>
        <li>Reframed the introduction around hops with no authorization
        server, and added <xref target="aims-relationship"/> on the
        relationship to AIMS. The draft-01 name for the token is no longer
        used; this revision calls it a delegation chain token.</li>
        <li>Added an encoding-neutral delegation chain model
        (<xref target="chain-model"/>) with one attenuation invariant,
        inheritance, and wildcard rules. Restated V1 through V7 over it,
        with V1 defined per encoding and V6 split into a structural part
        and a Datalog part.</li>
        <li>Added the JWT chain encoding (<xref target="jwt-chain"/>). The
        draft-01 compact mode is now a one-link JWT chain; the draft-01
        compact token is still accepted for this revision and is
        deprecated.</li>
        <li>Corrected the verification result: the JWT chain encoding
        authenticates the chain of holder keys, and delegator and delegate
        identity additionally requires checking each key against its
        identifier; the Biscuit encoding authenticates neither.</li>
        <li>Domains are now encoded: <tt>aip_domains</tt> in the JWT chain
        encoding and <tt>domain</tt> facts in the Biscuit encoding.</li>
        <li>Expiry is now checked structurally in V4 in both encodings.
        Previously it was enforced only through the Biscuit Datalog time
        check.</li>
        <li>An authority link with no tools is malformed. The Python
        implementation previously accepted it and imposed no tool
        constraint.</li>
        <li>An empty tools or domains list is malformed in any link.</li>
        <li>A Biscuit block that repeats a single-valued fact is
        malformed. A Biscuit delegation block MAY omit its tool check to
        inherit.</li>
        <li>The tool-check form for wildcard entries is now part of the
        canonical encoding.</li>
        <li>Error codes are written with the <tt>aip_</tt> prefix
        throughout, and every expiry failure returns
        <tt>aip_token_expired</tt>.</li>
        <li>Removed completion blocks, verification trust levels, and audit
        tokens, which were never implemented.</li>
        <li>Updated proof of possession: the JWT chain encoding names the
        holder key in <tt>cnf</tt>. Added security considerations on
        truncation, encoding-dependent identity guarantees, Datalog
        encoding, and conformance testing.</li>
        <li>The identity document signature encoding is stated as
        base64url.</li>
        <li>Stated that V2 binds a key to an issuer but does not make the
        issuer a trusted source of authority, which is the relying party's
        policy decision. Added Privacy Considerations.</li>
        <li>The HTTP binding carries the token as is rather than
        re-encoding it.</li>
        <li>Added <xref target="implementation-status"/>. Re-audited
        <xref target="cross-org-mapping"/> against the code and against
        the -02 revision of the requirements draft, including R7, which
        draft-01 recorded as met.</li>
        <li>The MCP binding states that the requested tool is "tool:"
        followed by the tool name.</li>
        <li>IANA: added media types application/aip-chain+jwt and
        application/aip-link+jwt and the JWT claim registrations.</li>
      </ul>
    </section>

    <section anchor="acknowledgements" numbered="false">
      <name>Acknowledgements</name>
      <t>The Biscuit authorization token specification influenced the
      Biscuit encoding. The MCP and A2A protocol teams provided the
      agent communication infrastructure that AIP extends.</t>
    </section>
  </back>
</rfc>
