<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc SYSTEM "rfc2629-xhtml.ent">
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="info" docName="draft-dias-agent-payment-verdicts-00" ipr="trust200902" submissionType="IETF" version="3" xml:lang="en" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="Agent Payment Verdicts">Signed Authorization Verdicts for Agent-Initiated Payments</title>
    <seriesInfo name="Internet-Draft" value="draft-dias-agent-payment-verdicts-00"/>
    <author fullname="Ithelia Dias" initials="I." surname="Dias">
      <organization>Saifuro LLC</organization>
      <address>
        <postal>
          <city>Sheridan</city>
          <region>WY</region>
          <country>United States of America</country>
        </postal>
        <email>ithelia.dias@saifuro.com</email>
        <uri>https://saifuro.com</uri>
      </address>
    </author>
    <date year="2026" month="October" day="9"/>
    <keyword>agent</keyword>
    <keyword>payment</keyword>
    <keyword>authorization</keyword>
    <keyword>JWT</keyword>
    <keyword>verdict</keyword>
    <abstract>
      <t>When a software agent initiates a payment on behalf of an
      organization, the party that settles the payment usually cannot see
      the policy under which it was permitted. This document describes a
      signed authorization verdict: a JSON Web Token, signed with ES256,
      that records the outcome of evaluating one payment request, including
      its amount, currency, and recipient, against a spending policy that
      the organization configured. A party holding the issuer's published
      public key can verify a verdict without contacting the issuer.</t>
      <t>The document describes the claim set, key publication and rotation,
      and a verification procedure, and states what a verdict does not
      assert. It describes the format as one implementation issues it,
      including the points where it departs from JSON Web Token Best Current
      Practices (RFC 8725). It is offered as input to IETF discussion of
      authorization records for agent-initiated actions and is not a
      proposal for standardization.</t>
    </abstract>
    <note removeInRFC="true">
      <name>Discussion Venues</name>
      <t>Comments are welcome by email to the author. Whether signed authorization decisions are in scope for the work proposed for a potential AUDIT BoF can be discussed on the audit@ietf.org list <xref target="AUDIT"/>.</t>
    </note>
  </front>
  <middle>
    <section anchor="intro">
      <name>Introduction</name>
      <t>Three properties of an agent-initiated payment can be checked
      separately: which agent initiated it, whether it was within the
      authority the agent was given, and whether value moved. The first and
      third are the subject of active protocol work
      (<xref target="related"/>). The second is usually decided inside the operator's own systems or a provider's, and the decision does not travel with the payment.</t>
      <t>This document describes a verdict: a signed statement, valid for a
      short time, that names the request it was made about, the mandate it was checked against, if any, and the outcome of the check. A party asked to settle the payment can check a verdict without contacting the issuer, using the issuer's published keys, its own record of the payment, a record of the verdicts it has already accepted, and, where the payment draws on a particular operator's funds, the mandate identifiers and amount unit agreed with that operator (<xref target="verify"/>). Refusals produced by policy evaluation are signed in the same way as approvals; an operator's refusal of a request held for review produces no verdict (<xref target="values"/>).</t>
      <t>This document is descriptive. It records the format that one
      implementation issues (<xref target="impl"/>), including the points
      where the format departs from <xref target="RFC8725"/> and other
      properties the author considers weaknesses
      (<xref target="security"/>, <xref target="open"/>). It is offered as
      input to IETF discussion of authorization records for agent actions,
      such as the discussion on the audit mailing list <xref target="AUDIT"/> of a potential AUDIT BoF and working group charter; in particular, <xref target="outcomes"/> and <xref target="asserts"/> state, for one deployed format, what a successful check establishes and what it does not. The author does not ask for this format to be
      adopted; a standard format in this area would need to resolve the
      issues in <xref target="open"/> and might not be compatible with this
      one.</t>
      <t>The author is the founder of Saifuro LLC, which operates the
      implementation described here, and has a commercial interest in this
      area.</t>
      <section anchor="scope">
        <name>Scope</name>
        <t>In scope are the verdict format (<xref target="format"/>), the
        publication of verification keys (<xref target="keys"/>), and the
        procedure a relying party follows before it relies on a verdict
        (<xref target="verify"/>).</t>
        <t>Out of scope are: the language in which spending policy is
        expressed; how an agent authenticates to the issuer; user consent;
        how a payment is executed or settled; how a verdict is carried inside
        a particular payment protocol; and the identity of an agent beyond an
        identifier assigned by its operator. The issuer described here does
        not hold or move funds, and a verdict is not a payment
        instrument.</t>
      </section>
      <section anchor="reqs">
        <name>Requirements Language</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
        described in BCP&nbsp;14 <xref target="RFC2119"/>
          <xref target="RFC8174"/> when, and only when, they appear in all
        capitals, as shown here.</t>
        <t>In this document, BCP 14 key words state what a relying party has to do to rely safely on verdicts in this format. In Table 2, and where <xref target="request"/> says that members are <bcp14>REQUIRED</bcp14>, they state what a verdict contains: a verifier rejects a token in which a required claim or member is absent (<xref target="verify"/>, steps 4 and 6). <xref target="rotation"/>, <xref target="sec-bearer"/>, and <xref target="privacy"/> also address operators and others that carry or keep verdicts. The key words do not define requirements for other issuers or formats.</t>
      </section>
      <section anchor="terms">
        <name>Terminology</name>
        <dl newline="false" spacing="normal">
          <dt>Operator:</dt>
          <dd>The organization that runs an agent and configures the
          authority it has to spend.</dd>
          <dt>Agent:</dt>
          <dd>Software that proposes payments on an operator's behalf.</dd>
          <dt>Mandate:</dt>
          <dd>An operator-configured policy object at the issuer that limits
          what one agent may spend. In the deployed implementation it holds a
          per-transaction limit and an optional rolling 30-day limit in one
          currency, a list of allowed categories, an expiry date, an optional review threshold, and the name of the principal expected to approve reviews (<xref target="sec-review"/>). It does not restrict recipients. Mandates are not edited, only revoked and
          replaced. A mandate in this sense is not the same object as the
          mandates of <xref target="AP2"/>, and it is not a credential signed
          by a user.</dd>
          <dt>Environment:</dt>
          <dd>One of the issuer's separately keyed instances, test ("sandbox")
          or production. Each operator has its own agents and mandates in
          each.</dd>
          <dt>Issuer:</dt>
          <dd>The service that evaluates a payment request against the
          operator's mandates and signs the result; in the terminology of
          <xref target="AUTHZEN"/>, a policy decision point.</dd>
          <dt>Verdict:</dt>
          <dd>The signed token defined in <xref target="format"/>. "Verdict
          code" means the value of its verdict claim.</dd>
          <dt>Relying party:</dt>
          <dd>The party that is about to settle, ship, or release funds on
          the strength of a verdict: for example a seller, a payment service
          provider, or an escrow release process.</dd>
          <dt>Verifier:</dt>
          <dd>The component of a relying party that performs
          <xref target="verify"/>.</dd>
          <dt>Payment record:</dt>
          <dd>The relying party's own record of the payment it is about to
          settle: amount, currency, and recipient. It comes from the relying party's systems, never from the token.</dd>
        </dl>
        <t>Names of claims, members of request, and header parameters that this format or its event tokens (<xref target="sec-events"/>) use are written without quotation marks (iss, request.amount, kid); values, and names that the format does not use, are written in quotation marks ("ES256", "allow", "aud").</t>
      </section>
    </section>
    <section anchor="related">
      <name>Related Work</name>
      <t>Several specifications address agent-initiated payments, or authorization decisions in general, at different points: when a user authorizes a purchase or delegates authority to an agent (<xref target="AP2"/>), when a payment credential is handed to a merchant's payment service provider (<xref target="ACP"/>), on individual requests (<xref target="RFC9421"/>, <xref target="TAP"/>, <xref target="X402"/>), and when authorization is requested or decided (<xref target="RFC9396"/>, <xref target="AUTHZEN"/>). Not all of them define a signed object. The descriptions
      below are based on the cited public specifications as accessed on 7
      October 2026, and on 9 October 2026 for <xref target="I-D.laxsharma-pact"/>.</t>
      <dl newline="true" spacing="normal">
        <dt>OAuth 2.0 Rich Authorization Requests <xref target="RFC9396"/>:</dt>
        <dd>A client requests fine-grained authorization, for example to
        initiate a single payment, from an authorization server, usually with
        the resource owner's consent, and presents the resulting access token
        to a resource server that trusts that authorization server. A verdict
        is not an access token: it records the outcome of a policy
        evaluation, including refusals, and is meant to be checked by a
        relying party whose only relationship with the issuer is holding its
        public keys.</dd>
        <dt>Transaction Tokens <xref target="I-D.ietf-oauth-transaction-tokens"/>:</dt>
        <dd>Carry user identity, workload identity, and authorization context
        between workloads within a single trust domain. A verdict is meant to
        be verified outside the issuing organization, by a party that does
        not share its trust domain.</dd>
        <dt>OpenID AuthZEN Authorization API 1.0 <xref target="AUTHZEN"/>:</dt>
        <dd>Defines how a policy enforcement point asks a policy decision
        point for a decision, which is returned as JSON. It permits a
        decision point to sign its response (Section 11.6 of
        <xref target="AUTHZEN"/>) but does not define a signed response
        format. A verdict can be read as a signed decision about a payment,
        meant to be verified further downstream than the enforcement point
        that requested it.</dd>
        <dt>Agent Payments Protocol <xref target="AP2"/>:</dt>
        <dd>Carries the user's authorization as signed mandates that the
        merchant, the credential provider, and the payment network verify. A
        verdict instead carries the result of an evaluation performed by the
        issuer against the operator's policy, without disclosing the policy.
        It carries no user consent and can accompany such mandates without
        replacing them.</dd>
        <dt>Agentic Commerce Protocol <xref target="ACP"/>:</dt>
        <dd>In its delegated payment specification, the agent platform sends
        a payment credential to the merchant's payment service provider with
        a single-use allowance (a maximum amount, a currency, a checkout
        session, a merchant, and an expiry), and the provider restricts the
        resulting token to that allowance. A verdict is a separate token that
        the relying party verifies itself before settlement.</dd>
        <dt>x402 <xref target="X402"/>:</dt>
        <dd>The client signs a scheme-specific payment authorization, and the
        resource server verifies and settles the payment, either itself or
        through a facilitator. That signature is the payer's authorization of
        the transfer. A verdict authorizes no transfer; it is a statement by
        a third party about a policy evaluation, signed by neither the payer
        nor the payee.</dd>
        <dt>HTTP Message Signatures <xref target="RFC9421"/>, Web Bot Auth <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>, and Trusted Agent Protocol <xref target="TAP"/>:</dt>
        <dd>Let a server authenticate an automated client's HTTP requests.
        <xref target="TAP"/> profiles HTTP Message Signatures so that a
        merchant can recognize an agent's requests using public keys that the payment network publishes, and adds signed objects that identify the consumer and
        carry payment data. A verdict identifies neither the agent's software
        nor the consumer; it states the outcome of a policy evaluation.</dd>
        <dt>Auditing and transparency:</dt>
        <dd>
          <xref target="I-D.kuehlewind-audit-architecture"/> describes an
        architecture for auditing agent delegation and interactions; a
        verdict is one kind of record such an architecture could carry or
        reference. <xref target="RFC9943"/> describes registering signed
        statements with a transparency service that issues receipts, using COSE rather than JOSE. It addresses long-term verification, which this format leaves to each party that stores its own copy of the JWK Set (<xref target="rotation"/>, <xref target="sec-trust"/>).</dd>
        <dt>PACT <xref target="I-D.laxsharma-pact"/>:</dt>
        <dd>Uses the term "Verdict" for a different object: a signed record
        in which an evaluator judges whether work an agent delivered under a
        task contract passes or fails. PACT does not address payments or
        their authorization, and the two formats are unrelated apart from
        the term.</dd>
      </dl>
    </section>
    <section anchor="overview">
      <name>Overview</name>
      <figure anchor="fig-flow">
        <name>Issuing and checking a verdict</name>
        <artwork type="ascii-art" align="left">
  Agent               Issuer               Relying Party
    |                   |                        |
    | (1) request       |                        |
    |------------------&gt;|                        |
    |                   | (2) evaluate against   |
    |                   |     the mandates       |
    | (3) verdict (JWS) |                        |
    |&lt;------------------|                        |
    |                   |                        |
    | (4) payment, verdict attached              |
    |-------------------------------------------&gt;|
    |                   | (5) JWK Set (cached)   |
    |                   |&lt;-----------------------|
    |                   |-----------------------&gt;|
    |                   |                        | (6) verify,
    |                   |                        |     compare with
    |                   |                        |     payment record
</artwork>
      </figure>
      <ol spacing="normal">
        <li>The agent sends a payment request, stating amount, currency,
        recipient, and category, to the issuer.</li>
        <li>The issuer evaluates the request against the agent's mandates
        and records the decision.</li>
        <li>The issuer returns the decision, including a verdict. A verdict is
        issued for every evaluated request, whatever the outcome.</li>
        <li>The agent, or a component acting for the operator, presents the
        verdict to the relying party together with the payment.</li>
        <li>The relying party obtains the issuer's JWK Set, normally from its
        cache.</li>
        <li>The relying party verifies the verdict and compares it with its
        payment record (<xref target="verify"/>).</li>
      </ol>
      <t>The relying party needs no account with the issuer and sends it no request about individual verdicts: from the issuer it needs only the published JWK Set. It also needs its own payment record, its store of accepted nonces, and, for step 8 of <xref target="verify"/>, the mandate identifiers and the amount unit it has agreed with the operator.</t>
      <t><xref target="tab-constants"/> collects the values that this document refers to: those of the deployed implementation, and those this document sets for verifiers.</t>
      <table anchor="tab-constants">
        <name>Values referred to in this document</name>
        <thead>
          <tr>
            <th>Value</th>
            <th>Setting</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Verdict lifetime (exp - iat)</td>
            <td>300 seconds</td>
          </tr>
          <tr>
            <td>Clock skew allowed to verifiers</td>
            <td>at most 60 seconds</td>
          </tr>
          <tr>
            <td>Review expiry</td>
            <td>24 hours</td>
          </tr>
          <tr>
            <td>Frequency rule</td>
            <td>10 decisions per agent in 60 seconds</td>
          </tr>
          <tr>
            <td>Window of the rolling limit</td>
            <td>30 days</td>
          </tr>
          <tr>
            <td>JWK Set cache lifetime (max-age)</td>
            <td>300 seconds</td>
          </tr>
          <tr>
            <td>Refetches on unknown kid</td>
            <td>at most one per 30 seconds (recommended)</td>
          </tr>
          <tr>
            <td>Pre-publication of a new key</td>
            <td>at least 1 hour</td>
          </tr>
          <tr>
            <td>Retention of a retired key</td>
            <td>at least 25 hours after its last token</td>
          </tr>
          <tr>
            <td>Redelivery of event tokens</td>
            <td>last retry due 24 hours after creation</td>
          </tr>
          <tr>
            <td>Identifier prefixes</td>
            <td>"dec_", "mnd_", "n_", "agt_", "evt_"</td>
          </tr>
          <tr>
            <td>Nonce</td>
            <td>64 random bits</td>
          </tr>
          <tr>
            <td>Amount</td>
            <td>greater than 0, less than 10^15, at most 6 fractional digits</td>
          </tr>
          <tr>
            <td>Idempotency-Key retention</td>
            <td>24 hours</td>
          </tr>
          <tr>
            <td>API request body limit</td>
            <td>64 KB</td>
          </tr>
          <tr>
            <td>Length of recipient; of category and currency</td>
            <td>at most 1,024 characters; at most 128 characters each</td>
          </tr>
        </tbody>
      </table>
    </section>
    <section anchor="format">
      <name>Verdict Format</name>
      <section anchor="header">
        <name>Serialization, Header, and Signature</name>
        <t>A verdict is a JSON Web Token (JWT) <xref target="RFC7519"/> in JWS
        Compact Serialization <xref target="RFC7515"/>: three base64url
        segments without padding, separated by periods.</t>
        <t>The issuer emits exactly three header parameters: alg, with the value "ES256" (ECDSA using P-256 and SHA-256,
        <xref target="RFC7518" section="3.4"/>); typ, with the value "JWT"; and kid, naming the signing key in the issuer's JWK Set
        (<xref target="keys"/>). It does not emit "crit", "jku", "jwk", "x5u",
        "x5c", "x5t", "cty", or any other header parameter. The typ value does
        not distinguish a verdict from other tokens signed with the same key
        (<xref target="sec-typ"/>).</t>
        <t>The signature is the 64-byte concatenation of R and S, each 32
        bytes, big-endian, as <xref target="RFC7518" section="3.4"/>
        requires, not an ASN.1 DER encoding. The issuer uses randomized ECDSA
        (<xref target="sec-alg"/>) and does not normalize S
        (<xref target="sec-replay"/>).</t>
        <t>The payload is a JSON object <xref target="RFC8259"/> encoded in
        UTF-8 <xref target="RFC3629"/>. The issuer writes it without
        insignificant whitespace and in the member order of
        <xref target="tab-claims"/>. Verifiers <bcp14>MUST NOT</bcp14> depend
        on member order, whitespace, or string escaping.</t>
      </section>
      <section anchor="claims">
        <name>Claims</name>
        <table anchor="tab-claims">
          <name>Verdict claims</name>
          <thead>
            <tr>
              <th>Claim</th>
              <th>Type</th>
              <th>Presence</th>
              <th>Meaning</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>iss</td>
              <td>string</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Issuer identifier.</td>
            </tr>
            <tr>
              <td>jti</td>
              <td>string</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Identifier the issuer assigns to the decision. Unique per
                verdict.</td>
            </tr>
            <tr>
              <td>iat</td>
              <td>integer</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Time of the decision; for an "allow" that approves a
                review, the time of the approval.</td>
            </tr>
            <tr>
              <td>exp</td>
              <td>integer</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Expiry, on every verdict whatever its code.</td>
            </tr>
            <tr>
              <td>verdict</td>
              <td>string</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Verdict code (<xref target="values"/>).</td>
            </tr>
            <tr>
              <td>mandate</td>
              <td>string</td>
              <td>see <xref target="presence"/></td>
              <td>Identifier of the mandate whose evaluation produced the
                verdict.</td>
            </tr>
            <tr>
              <td>policy_version</td>
              <td>string</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Per-operator label; opaque to verifiers.</td>
            </tr>
            <tr>
              <td>nonce</td>
              <td>string</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>Random value generated for each verdict; the replay key
                (<xref target="verify"/>, step 12).</td>
            </tr>
            <tr>
              <td>request</td>
              <td>object</td>
              <td>
                <bcp14>REQUIRED</bcp14></td>
              <td>The payment request that was evaluated
                (<xref target="request"/>).</td>
            </tr>
            <tr>
              <td>supersedes</td>
              <td>string</td>
              <td>see <xref target="presence"/></td>
              <td>The jti of the "review" verdict that this "allow"
                resolves.</td>
            </tr>
          </tbody>
        </table>
        <t>In Table 2 and in step 6 of <xref target="verify"/>, "integer" means a JSON number whose value is an integer; the issuer writes such values with no fraction or exponent part. This narrows NumericDate
        (<xref target="RFC7519" section="2"/>), which also allows
        non-integer values.</t>
        <t>In the deployed implementation, policy_version is assigned once per
        operator and is not updated when mandates change; despite its name, it
        does not identify the rules that were applied. Because mandates are
        not edited, the mandate claim identifies the limits that were
        evaluated. Verifiers <bcp14>MUST</bcp14> treat policy_version as an
        opaque string. The nonce is 64 random bits in the deployed
        implementation; jti is enforced unique by the issuer.</t>
        <t>The claims iss, jti, iat, and exp are used with their registered
        meanings (<xref target="RFC7519" section="4.1"/>). The claim nonce is
        registered in the IANA "JSON Web Token Claims" registry by
        <xref target="OIDC-CORE"/>; <xref target="RFC9449" section="12.7.1"/> updated the registration to state that it may also be used for nonce
        values in other applications of JWTs, and it is used here in that
        sense, as a non-repeating value used to detect replay. Unlike the
        nonce of <xref target="OIDC-CORE"/> and <xref target="RFC9449"/>,
        which is supplied by the party that later checks the token, this
        nonce is chosen by the issuer, so it gives the relying party no
        assurance of freshness beyond exp. The claims verdict, mandate,
        policy_version, request, and supersedes are Private Claim Names
        (<xref target="RFC7519" section="4.3"/>) and can collide with other
        uses of the same names (<xref target="open"/>).</t>
        <t>Apart from the "sandbox-" prefix of kid (step 3 of <xref target="verify"/>) and the "evt_" prefix of jti (step 6), verifiers <bcp14>SHOULD</bcp14> treat identifiers as opaque strings.</t>
        <t>Verifiers <bcp14>MUST</bcp14> ignore private claims, and members of request, that they do not understand (<xref target="versioning"/>). Registered claims that verdicts do not carry are processed as <xref target="RFC7519"/> specifies: a verdict carrying "aud" is rejected unless the verifier identifies itself with one of its values (<xref target="RFC7519" section="4.1.3"/>), and one carrying "nbf" is rejected before that time (<xref target="RFC7519" section="4.1.5"/>).</t>
      </section>
      <section anchor="request">
        <name>The request Claim</name>
        <table anchor="tab-request">
          <name>Members of the request claim</name>
          <thead>
            <tr>
              <th>Member</th>
              <th>Type</th>
              <th>Meaning</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>agent</td>
              <td>string</td>
              <td>Identifier of the agent, unique among one operator's
                agents in one environment.</td>
            </tr>
            <tr>
              <td>amount</td>
              <td>number</td>
              <td>Amount evaluated (<xref target="amounts"/>).</td>
            </tr>
            <tr>
              <td>currency</td>
              <td>string</td>
              <td>Currency or asset code, exactly as the request stated it.
                When the mandate claim is present, it equals that mandate's
                currency.</td>
            </tr>
            <tr>
              <td>recipient</td>
              <td>string</td>
              <td>Payee identifier, exactly as sent in the request.</td>
            </tr>
            <tr>
              <td>category</td>
              <td>string</td>
              <td>Spending category, exactly as sent in the request.</td>
            </tr>
          </tbody>
        </table>
        <t>All five members are <bcp14>REQUIRED</bcp14>.</t>
        <t>The issuer matches currency against the mandate's currency by
        exact, case-sensitive comparison, and does not normalize the value or
        restrict it to a list of codes. The issuer's documentation uses
        uppercase ISO 4217 codes such as "USD", and "USDC" for an asset that
        has no ISO 4217 code. Other specifications use other forms, for
        example lowercase codes and integer minor units in
        <xref target="ACP"/>; a relying party that holds its payment record in another form converts the currency code to this form, and the amount to the unit agreed with the operator (<xref target="amounts"/>; <xref target="verify"/>, step 8), before steps 9 and 10 of <xref target="verify"/>; that conversion is part of its own code.</t>
        <t>The format of recipient is agreed between the operator and the
        relying party; examples are "vendor:acme_saas" and a wallet address.
        The issuer does not check it against the identity of any party
        (<xref target="sec-payee"/>).</t>
        <t>In the deployed implementation's test environment, creating an
        escrow is also evaluated. Such a verdict carries the escrow's seller
        as recipient and the fixed category "escrow", and the evaluation
        skips the category check.</t>
      </section>
      <section anchor="presence">
        <name>Presence by Verdict Code</name>
        <table anchor="tab-presence">
          <name>Conditional claims</name>
          <thead>
            <tr>
              <th>Verdict code</th>
              <th>mandate</th>
              <th>supersedes</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>allow, from an evaluation</td>
              <td>present</td>
              <td>absent</td>
            </tr>
            <tr>
              <td>allow, from approving a review</td>
              <td>present</td>
              <td>present</td>
            </tr>
            <tr>
              <td>review</td>
              <td>present</td>
              <td>absent</td>
            </tr>
            <tr>
              <td>deny_limit, deny_velocity, deny_category, deny_expired,
                deny_revoked</td>
              <td>present</td>
              <td>absent</td>
            </tr>
            <tr>
              <td>deny_no_mandate</td>
              <td>absent</td>
              <td>absent</td>
            </tr>
          </tbody>
        </table>
      </section>
      <section anchor="values">
        <name>Verdict Codes</name>
        <table anchor="tab-values">
          <name>Verdict codes</name>
          <thead>
            <tr>
              <th>Code</th>
              <th>Meaning</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>allow</td>
              <td>The request passed every check in this table, or it was held for review and the operator approved it (<xref target="sec-review"/>). The only code on which a relying party may settle.</td>
            </tr>
            <tr>
              <td>review</td>
              <td>The amount is above the mandate's review threshold, and
                the operator must approve or deny the request. Not an
                approval.</td>
            </tr>
            <tr>
              <td>deny_limit</td>
              <td>The amount exceeds the per-transaction limit, or, together
                with the amounts allowed under the same mandate in the
                previous 30 days, the rolling 30-day limit.</td>
            </tr>
            <tr>
              <td>deny_velocity</td>
              <td>The agent already had 10 or more decisions in the previous
                60 seconds.</td>
            </tr>
            <tr>
              <td>deny_category</td>
              <td>The category is not one of the mandate's allowed
                categories.</td>
            </tr>
            <tr>
              <td>deny_expired</td>
              <td>The mandate is past its expiry date.</td>
            </tr>
            <tr>
              <td>deny_revoked</td>
              <td>The mandate has been revoked.</td>
            </tr>
            <tr>
              <td>deny_no_mandate</td>
              <td>The agent is not active, holds no mandate, or holds no
                mandate in the requested currency.</td>
            </tr>
          </tbody>
        </table>
        <t>For each of the agent's mandates in the requested currency, the
        checks run in this order: revoked, expired, category, per-transaction
        limit, rolling 30-day limit, frequency rule, review threshold. When the agent holds several such mandates, they are evaluated in order of creation, and the verdict is the first "allow", otherwise the first "review", otherwise the result for the oldest mandate. These checks are the whole of the evaluation; in
        particular, a mandate does not restrict the recipient
        (<xref target="sec-payee"/>).</t>
        <t>A relying party <bcp14>MUST</bcp14> treat every code other than
        "allow", including codes this document does not define, as "do not
        settle".</t>
        <t>When the operator approves a review, the issuer issues a new
        verdict with the code "allow", its own nonce and expiry, and a
        supersedes claim naming the "review" verdict
        (<xref target="sec-review"/>). The "review" verdict is not modified. A
        review that the operator denies, or that expires, produces no
        verdict.</t>
        <t>An operator records, per environment, a mode of "observe" or
        "enforce", which tells its own systems whether to block payments that
        are not allowed; the issuer blocks nothing in either mode. In the
        deployed implementation, a production environment is in observe mode
        until the operator changes it. The issuer evaluates, records, and
        signs the same verdicts in either mode, and the mode is not in the
        token, so a signed refusal does not show that a payment was
        blocked.</t>
      </section>
      <section anchor="amounts">
        <name>Amounts</name>
        <t>request.amount is a JSON number in the same units as the mandate's
        limits. The issuer does not interpret or convert units; its
        documentation uses major units, so that 340 with currency "USD" means
        340 US dollars, not 340 cents. The amount is greater than zero and less
        than 10^15, and has at most six fractional digits. The issuer writes it
        in minimal fixed-point form: an integral amount has no decimal point
        (340, never 340.00), other amounts have no trailing zeros (340.5,
        never 340.50), and the issuer never uses exponent notation or leading zeros other than the single 0 before the decimal point of an amount below 1 (0.5).</t>
        <t>Amounts can therefore carry up to 21 significant digits, more than
        an IEEE 754 binary64 number holds. This departs from
        <xref target="RFC7493" section="2.2"/>, which says that I-JSON
        messages should not include such numbers and recommends JSON strings
        for them. Many JSON parsers, including those inside common JWT
        libraries, read every number as binary64, and from 2^33 (about 8.6 x 10^9) upward two amounts that differ in the sixth fractional digit can map to the same binary64 value; 8589934592.000001 and 8589934592.000002 do. A
        verifier therefore compares amounts by decimal value
        (<xref target="verify"/>, step 9).</t>
        <t>Nothing in the token states the unit. An operator that configures a mandate in minor units obtains verdicts whose amounts are in minor units, and a relying party that compares them with a payment record in major units (<xref target="verify"/>, step 9) would match a verdict evaluated for 340 cents against a payment of 340 US dollars. Step 8 of <xref target="verify"/> therefore includes agreeing the unit with the operator.</t>
      </section>
      <section anchor="not-in-token">
        <name>What the Token Does Not Contain</name>
        <t>The issuer keeps information about each decision that is not in the
        token and is therefore not signed. The decision record it returns to
        the operator contains the enforcement mode
        (<xref target="values"/>), a human-readable reason, operator metadata
        such as order references, and, for a "review" verdict, the review
        identifier and the principal it waits for. The issuer also stores,
        but neither signs nor returns in the decision record, the payment
        protocol named in the request. A verdict is therefore not bound to an
        order, and a verdict evaluated for one payment protocol can be
        presented on another.</t>
        <t>The token has no "aud", "sub", "nbf", or "cnf" claim, and no claim
        that identifies the operator (<xref target="sec-operator"/>, <xref target="sec-bearer"/>, <xref target="sec-aud"/>).</t>
      </section>
    </section>
    <section anchor="keys">
      <name>Key Publication</name>
      <section anchor="jwks">
        <name>JWK Set</name>
        <t>The issuer publishes its public keys as a JWK Set
        (<xref target="RFC7517" section="5"/>). Each key has "kty" "EC",
        "crv" "P-256", "x", "y", "use" "sig", "alg" "ES256", and a "kid". The
        deployed implementation serves the set over HTTPS with
        "Cache-Control: public, max-age=300" <xref target="RFC9111"/> and
        "Access-Control-Allow-Origin: *", with the media type
        "application/json" rather than "application/jwk-set+json"
        (<xref target="RFC7517" section="8.5"/>).</t>
      </section>
      <section anchor="locating">
        <name>Locating the JWK Set</name>
        <t>The deployed implementation publishes its JWK Set at the path "/.well-known/jwks.json" under its issuer identifier, https://verdicts.saifuro.com (<xref target="impl"/>), and keeps an older location that permanently redirects to it. The suffix "jwks.json" is widely used but is
        not registered in the Well-Known URIs registry; serving the set under
        it departs from <xref target="RFC8615" section="3"/>, which requires
        registration, and this document does not register it (<xref target="open"/>).</t>
        <t>A relying party <bcp14>MUST</bcp14> take the list of issuers it
        accepts, and the JWK Set location for each, from its own
        configuration, and <bcp14>MUST</bcp14> fetch each set over HTTPS with
        certificate validation. It <bcp14>MUST NOT</bcp14> fetch keys from a
        location derived from a token. Otherwise any party can mint verdicts that verify against keys it publishes itself. A verifier <bcp14>SHOULD NOT</bcp14> follow HTTP redirects when fetching a JWK Set, since a redirect moves the source of its keys to a location that is not in its configuration, and <bcp14>SHOULD</bcp14> bound the size of the response and the time it waits for it.</t>
      </section>
      <section anchor="environments">
        <name>Test and Production Keys</name>
        <t>The deployed implementation operates a test environment and a
        production environment. Each has its own signing key, and both keys
        are published in the same JWK Set. The kid of a test key begins with
        "sandbox-"; the kid of a production key does not. The issuer
        identifier, the claim set, and the token shape are otherwise
        identical. Anyone with access to the test environment can obtain a
        correctly signed test "allow" for any recipient and amount, so a verifier rejects tokens whose kid begins with "sandbox-" unless it is used only for testing
        (<xref target="verify"/>, step 3; <xref target="sec-typ"/>).</t>
      </section>
      <section anchor="caching">
        <name>Caching and Unknown Key Identifiers</name>
        <t>Verifiers <bcp14>SHOULD</bcp14> cache each JWK Set and refresh it
        when it is older than the max-age it was served with. If a refresh
        fails, a verifier <bcp14>MAY</bcp14> keep using the last copy it
        fetched successfully, <bcp14>SHOULD</bcp14> raise an alert, and
        <bcp14>SHOULD</bcp14> stop accepting verdicts once that copy is older
        than a bound it chooses: the longer it uses a stale copy, the longer a
        key the issuer has removed stays trusted (<xref target="sec-keys"/>).</t>
        <t>The kid is untrusted input, used only as a lookup key, never in a
        file path, query, or URL (<xref target="RFC8725" section="3.10"/>).
        On a kid that is absent from the cached set, a verifier fetches the
        set again once and looks again. Because anyone can send a token with
        any kid, these refetches <bcp14>MUST</bcp14> be rate-limited; an
        interval of at least 30 seconds between refetches triggered by unknown
        kids is <bcp14>RECOMMENDED</bcp14>, and scheduled refreshes
        <bcp14>SHOULD NOT</bcp14> count against that limit. Because the
        refetch is rate-limited, a stream of tokens with made-up kids can delay
        acceptance of a verdict signed with a key the verifier has not yet
        fetched; pre-publication (<xref target="rotation"/>) avoids that for
        verifiers that refresh on schedule.</t>
        <t>Pinning a single key in code is <bcp14>NOT RECOMMENDED</bcp14>: an
        integration that does so rejects valid verdicts after the next
        rotation.</t>
      </section>
      <section anchor="rotation">
        <name>Rotation</name>
        <t>The issuer's rotation procedure extends the approach of Section 10.1.1 of <xref target="OIDC-CORE"/>, in which a verifier
        refetches the set on an unfamiliar kid, with a period of
        pre-publication:</t>
        <ol spacing="normal">
          <li>The issuer publishes the new key in the set at least one hour
          before it signs anything with it, so that every verifier that
          refreshes on schedule holds the key before the first token signed
          with it.</li>
          <li>It switches signing to the new kid.</li>
          <li>It keeps the previous key in the set for at least 360 seconds
          after the last verdict that key signed (the 300-second lifetime of a
          verdict plus the 60-second maximum clock skew allowed in
          <xref target="verify"/>), and for as long as any event token it
          signed can still be delivered (<xref target="sec-events"/>). The deployed implementation's procedure keeps it for at least 25 hours after the last token of either kind.</li>
          <li>It removes the previous key.</li>
        </ol>
        <t>The deployed implementation has not yet rotated a key
        (<xref target="impl"/>), so this procedure has not been
        exercised.</t>
        <t>The set carries only keys that are about to be used, in use, or recently retired. A
        party that keeps verdicts as records, for audit or disputes,
        <bcp14>SHOULD</bcp14> store a copy of the JWK Set with them, so that
        the signatures can be checked after the key has been removed
        (<xref target="stored"/>).</t>
      </section>
    </section>
    <section anchor="verify">
      <name>Verification Procedure</name>
      <t>The inputs to verification are the token; the configured list of
      accepted issuers with the JWK Set of each; the current time from a
      synchronized clock; the payment record; a store of nonces from verdicts already accepted; whether the verifier is used only for testing; where step 8 requires them, the mandate identifiers agreed with the operator and the unit its mandates use; and, for the check of <xref target="sec-review"/>, a store of the supersedes values of verdicts already accepted.</t>
      <t>A relying party <bcp14>MUST</bcp14> apply every step below before
      it relies on a verdict, and <bcp14>MUST</bcp14> reject the token if any
      step fails. It <bcp14>MAY</bcp14> perform the steps in a different
      order, provided that it verifies the signature (step 5) before it
      relies on any claim, and records the nonce (step 12) only after every
      other step has passed. Every check <bcp14>MUST</bcp14> use values taken from the payload bytes whose signature step 5 verified. A verifier that parses those bytes more than once, for example with a JWT library for steps 4 and 7 and with a decimal-preserving parser for step 9, <bcp14>MUST</bcp14> reject a header or payload that contains duplicate member names at any depth, so that the parses cannot disagree about which member they read.</t>
      <ol spacing="normal">
        <li>Parse. Bound the size of the token before decoding it (verdicts that the deployed implementation issues are shorter than 11,000 characters; <xref target="sec-parse"/>), and bound the nesting depth of JSON that is parsed before the signature is verified. Split the
        token into exactly three segments. Decode each as base64url without
        padding (<xref target="RFC7515" section="2"/>), rejecting padding,
        whitespace, any character outside the base64url alphabet, and a
        segment whose length is 1 modulo 4; many base64 decoders accept these,
        so a verifier that uses one checks the segments itself. A verifier
        <bcp14>MAY</bcp14> reject a segment whose unused trailing bits are not
        zero. Decode the header and payload as UTF-8, rejecting invalid UTF-8
        (<xref target="RFC8725" section="3.7"/>). Each <bcp14>MUST</bcp14>
        parse as a JSON object. Header parameter and claim names
        <bcp14>MUST</bcp14> be unique: a verifier <bcp14>MUST</bcp14> either
        reject a header or payload with duplicate member names or use a
        parser that keeps only the lexically last one
        (<xref target="RFC7515" section="4"/>,
        <xref target="RFC7519" section="4"/>), and <bcp14>SHOULD</bcp14>
        reject duplicates at any depth.</li>
        <li>Header. The alg value <bcp14>MUST</bcp14> be exactly "ES256", compared
        case-sensitively (<xref target="RFC7515" section="4.1.1"/>). The
        accepted algorithms <bcp14>MUST</bcp14> come from the verifier's
        configuration for the issuer, never from the token, and the key
        selected in step 4 <bcp14>MUST</bcp14> be one the verifier uses only
        with ES256 (<xref target="RFC8725" section="3.1"/>). Reject a token
        that has a "crit" parameter (<xref target="RFC7515" section="4.1.11"/>).
        The kid value <bcp14>MUST</bcp14> be a non-empty string. Keys
        <bcp14>MUST NOT</bcp14> be taken from "jku", "jwk", "x5u", or "x5c",
        and verifiers <bcp14>SHOULD</bcp14> reject tokens that carry them.
        Verifiers do not use typ to identify a verdict
        (<xref target="sec-typ"/>).</li>
        <li>Environment. Unless the verifier is used only for testing, reject a token whose kid begins with "sandbox-"
        (<xref target="environments"/>).</li>
        <li>Issuer and key. The iss claim <bcp14>MUST</bcp14> equal, exactly, the
        identifier of an issuer in the verifier's configuration, compared as a
        case-sensitive string with no transformations or canonicalizations
        (<xref target="RFC7519" section="2"/>). Find the key with the token's
        kid in that issuer's JWK Set, and only there: a verifier that accepts
        more than one issuer <bcp14>MUST NOT</bcp14> look up the kid in the
        union of their key sets. This is the binding of keys to an issuer that
        <xref target="RFC8725" section="3.8"/> requires; iss is read before
        the signature is verified and is authenticated by step 5. The key
        <bcp14>MUST</bcp14> have "kty" "EC" and "crv" "P-256"; if it has
        "alg", the value <bcp14>MUST</bcp14> be "ES256"; if it has "use", the
        value <bcp14>MUST</bcp14> be "sig". If the kid is absent, refetch the
        set once under the rate limit of <xref target="caching"/>; reject the
        token if the rate limit does not permit a refetch, if the kid is still
        absent, or if it appears more than once.</li>
        <li>Signature. Verify the signature as ES256
        (<xref target="RFC7518" section="3.4"/>). The signature
        <bcp14>MUST</bcp14> be exactly 64 bytes. The verifier
        <bcp14>MUST</bcp14> reject a signature in which R or S is not an
        integer in the interval [1, n-1], where n is the order of the P-256
        group (Section 4.1.4 of <xref target="SEC1"/>); an implementation that
        omitted this check accepted an all-zero signature for any message (CVE-2022-21449; <xref target="PSYCHIC"/>). Verifiers <bcp14>MUST NOT</bcp14>
        require S to be in the lower half of the group order: the issuer does
        not normalize S, and such a check rejects about half of genuine
        verdicts. Use an implementation that validates that the public key is
        a point on P-256 (<xref target="RFC8725" section="3.4"/>).</li>
        <li>Token kind and structure. Reject a token whose payload has a type
        claim or whose jti begins with "evt_": it is an event token signed
        with the same key (<xref target="sec-events"/>). The jti claim <bcp14>MUST</bcp14> be a non-empty string. The iat and exp claims <bcp14>MUST</bcp14> be integers with exp greater than iat; a verifier
        <bcp14>MAY</bcp14> reject a token whose exp minus iat exceeds 300.
        The verdict claim, policy_version, and nonce <bcp14>MUST</bcp14> be
        non-empty strings. The request claim <bcp14>MUST</bcp14> be an object whose
        agent, currency, recipient, and category are non-empty strings and
        whose amount is a number greater than zero. The mandate and supersedes claims, when present, <bcp14>MUST</bcp14> be non-empty strings. If the
        verdict claim is "allow", mandate <bcp14>MUST</bcp14> be present. If supersedes is present, the verdict claim <bcp14>MUST</bcp14> be "allow". Reject a token that carries an "aud" claim unless the verifier identifies itself with one of its values (<xref target="claims"/>).</li>
        <li>Time. With a clock skew allowance L of at most 60 seconds, reject
        the token if the current time is at or after exp + L
        (<xref target="RFC7519" section="4.1.4"/>), or if iat is later than the current time + L. If the token carries an "nbf" claim, reject it while the current time + L is before the time in "nbf". Expiry does not change a verdict's code: an
        expired verdict is rejected whatever its code.</li>
        <li>Decision and operator. Reject the token unless the verdict claim
        is "allow". If the payment draws on funds, credit, or an account of a
        particular operator, also reject it unless mandate is one of the
        identifiers that operator has agreed with the relying party (<xref target="sec-operator"/>). Without this check, a verdict that
        passes every other step shows only that some operator configured a
        mandate that allows the payment, and any operator can do that for any
        recipient and amount. The relying party also agrees with that operator the unit in which its mandates state amounts (<xref target="amounts"/>); where no particular operator is involved, nothing establishes the unit (<xref target="asserts"/>).</li>
        <li>Amount. Compare request.amount with the amount in the payment record, expressed in the unit agreed in step 8, if any, by decimal value: 340 equals 340.00, and 340 does not equal
        340.5. Read the amount from the verified payload bytes with a JSON
        parser that preserves the literal number or yields a decimal type;
        most JWT libraries return claims in which numbers are already
        binary64. The issuer never writes an amount with an exponent, more
        than 15 digits before the decimal point, or more than 6 after it; a
        verifier <bcp14>SHOULD</bcp14> reject such an amount before
        converting it to a decimal type, wherever it first converts it (step 6 compares it with zero), since some decimal implementations
        take time or memory proportional to the exponent. Verifiers
        <bcp14>MUST NOT</bcp14> compare amounts as binary floating-point
        numbers, except that a verifier <bcp14>MAY</bcp14> compare binary64 values when both amounts are below 2^30 (about 1.07 x 10^9) and both have at most six fractional digits: in that range, distinct amounts with at most six fractional digits map to
        distinct binary64 values.</li>
        <li>Currency. The member request.currency <bcp14>MUST</bcp14> equal the currency
        code in the payment record exactly, compared case-sensitively.</li>
        <li>Recipient. The member request.recipient <bcp14>MUST</bcp14> equal the payee
        identifier in the payment record, compared code point for code point,
        with no Unicode normalization, case folding, or trimming. It names the
        payee, not the verifier, and binds the verdict to the relying party
        only when the relying party is the payee
        (<xref target="sec-aud"/>).</li>
        <li>Replay. Reject the token if the pair of iss and nonce is in the
        store of accepted nonces. Otherwise record the pair in the same atomic
        operation that accepts the token, and keep it at least until exp + L.
        All verifier instances that could accept the same token
        <bcp14>MUST</bcp14> share the store, and a verifier that cannot read
        or write the store <bcp14>MUST</bcp14> reject the token. The replay
        key is a claim value, never the token string
        (<xref target="sec-replay"/>); jti is also unique per verdict, so
        recording jti instead of nonce gives the same protection. A relying party that applies <xref target="sec-review"/> checks and records the pair of iss and supersedes in the same atomic operation.</li>
      </ol>
      <t>JWT libraries perform most of steps 1, 2, 4, and 5, and the exp and "nbf" checks
      of step 7, when they are configured with the algorithm list ["ES256"], the accepted issuer, and a clock tolerance of at most 60 seconds. Some libraries, such as jose, check "aud" only when an audience is configured.
      Implementers need to check what their library leaves out: a library
      that is handed a key object cannot check that key's "alg" and "use"
      members or whether its kid appears twice in the set, and some libraries
      accept padded or whitespace-broken segments. Steps 3, 6, 8, 9, 10, 11, and 12 are the relying party's own code, and so is the iat check of step 7 where the library does not perform it.</t>
      <section anchor="outcomes">
        <name>Matched, Contradicted, and Unsupported</name>
        <t>For each property of the payment record that the relying party
        relies on, verification has one of three outcomes:</t>
        <dl newline="false" spacing="normal">
          <dt>Matched:</dt>
          <dd>a signed claim covers the property and agrees with the payment
          record.</dd>
          <dt>Contradicted:</dt>
          <dd>a signed claim covers the property and disagrees with the
          payment record.</dd>
          <dt>Unsupported:</dt>
          <dd>no signed claim covers the property.</dd>
        </dl>
        <t>A contradicted property causes rejection, by steps 9 to 11. An
        unsupported property is neither evidence of a problem nor evidence of
        correctness: the relying party has to establish it independently. In
        this format, amount, currency, and recipient can be matched or
        contradicted. The members request.agent and request.category are signed, but the
        payment record has no corresponding property, so they can be neither
        matched nor contradicted. The operator behind the verdict is
        unsupported unless the relying party maps the mandate claim to an
        operator through identifiers agreed out of band
        (<xref target="sec-operator"/>); the order, the payment protocol, and
        the identity of an intermediary relying party are always unsupported.
        A relying party <bcp14>SHOULD</bcp14> record which properties it took
        from its own records rather than from the signature, so that a later
        audit can tell the two apart.</t>
      </section>
      <section anchor="stored">
        <name>Checking a Stored Verdict</name>
        <t>A party that checks a verdict as a record rather than to settle a
        payment, such as an auditor examining a refusal, applies steps 1, 2, 4,
        5, and 6 using a copy of the JWK Set that contains the key
        (<xref target="rotation"/>), and step 3 if it needs to distinguish
        test verdicts. It evaluates step 7 against the time at which the
        verdict was received if that time was recorded, and otherwise does not apply step 7; it does not apply steps 8 to 12. It does not refetch a key set for a stored verdict: a kid missing from the stored copy is a failure. Verdicts that the deployed implementation issued before 09:12 UTC on 9 October 2026 may lack request.currency, may contain Unicode noncharacters, and may be up to about 94,000 characters long; a party checking one of them as a record applies step 6 without the currency requirement, and step 1 with a size bound that admits them. Unless the party obtained the copy of the JWK Set itself, a successful check shows only that the verdict matches the key set that the record keeper stored (<xref target="sec-trust"/>).</t>
      </section>
    </section>
    <section anchor="asserts">
      <name>What a Verdict Asserts</name>
      <t>A verdict that passes steps 1 to 6 of <xref target="verify"/> is a
      statement, signed by the holder of the signing key, that it evaluated a
      payment request with the stated agent, amount, currency, recipient, and
      category against the named mandate (none, for "deny_no_mandate") and
      reached the stated verdict code. For a verdict without supersedes, iat
      is the time of that evaluation; for an "allow" that carries supersedes,
      the evaluation took place when the superseded "review" verdict was issued, some of its checks were repeated at approval, and iat is the time of the operator's approval (<xref target="sec-review"/>). The signature shows that the statement was made, not that it is correct (<xref target="sec-trust"/>). In the terms used on the audit mailing list <xref target="AUDIT"/>, a verdict is an attestation, not a record that a relying party can recompute: neither the mandate's limits nor the history behind the rolling 30-day limit is in it. A verdict
      does not show:</t>
      <ul spacing="normal">
        <li>that an end user consented: no user key is involved;</li>
        <li>that the operator or the agent authorized the payment: neither
        signs the token, so it is not evidence of either's
        authorization;</li>
        <li>that the operator approved the recipient
        (<xref target="sec-payee"/>);</li>
        <li>that the category describes what is being bought: it is a label supplied with the request, and the relying party has nothing to compare it with;</li>
        <li>the unit of request.amount: the issuer does not interpret it, and an operator's mandates can use a different unit from the relying party's payment record (<xref target="amounts"/>);</li>
        <li>that the named agent made the request: in the deployed
        implementation, a request made with an operator-wide credential names
        the agent in its body;</li>
        <li>which operator requested it, or that the operator is the party
        paying the relying party (<xref target="sec-operator"/>);</li>
        <li>that the payment was made, settled, or delivered, or that funds
        exist;</li>
        <li>which payment protocol or order it was evaluated for
        (<xref target="not-in-token"/>);</li>
        <li>whether the operator's systems block payments that are not
        allowed (<xref target="values"/>);</li>
        <li>that the mandate is still in force when the verdict is verified:
        an "allow" remains valid until exp even if the mandate is revoked
        after it was issued, and the relying party has no way to learn of the
        revocation from the issuer;</li>
        <li>that the payment is not one of several, each within the
        per-transaction limit and below the review threshold, that together
        make up a larger purchase;</li>
        <li>that a collection of verdicts is complete: verdicts are returned only to the operator that requested them, through its API keys and webhook endpoints, and an operator's denial of a review produces no verdict.</li>
      </ul>
    </section>
    <section anchor="versioning">
      <name>Versioning and Extensibility</name>
      <t>The token carries no version number, and the format has no mechanism
      for signalling a change. Verifiers detect features by the presence of
      claims. An issuer can add private claims and members of request, which verifiers ignore if they do not understand them
      (<xref target="claims"/>), and verdict codes, which verifiers treat as
      "do not settle" (<xref target="values"/>).</t>
      <t>Because verifiers ignore private claims they do not understand, a new private claim that narrows when a verdict may be relied on constrains only verifiers updated to check it; until every relying party checks it, a verdict carrying it is accepted where it was not meant to be. Adding "aud" is incompatible in the other direction: verifiers that apply <xref target="RFC7519" section="4.1.3"/> without a configured audience reject every verdict that carries it. Adding either kind of claim is therefore an incompatible change, as are removing a claim and changing a claim's type or meaning. Explicit typing alone would not make such a version fail at verifiers built to this document, which do not check typ (<xref target="verify"/>, step 2); a new issuer identifier would (step 4). The deployed implementation announces changes that verifiers have to act on in its documentation <xref target="SAIFURO-VERIFY"/>, with the date from which they apply.</t>
    </section>
    <section anchor="impl" removeInRFC="true">
      <name>Implementation Status</name>
      <t>This section records the status of known implementations of the
      format described in this document 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 <xref target="RFC7942"/>, "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>Note to the RFC Editor: please also remove the reference to <xref target="RFC7942"/>.</t>
      <section anchor="impl-saifuro">
        <name>Saifuro</name>
        <dl newline="false" spacing="normal">
          <dt>Organization:</dt>
          <dd>Saifuro LLC. The author is its founder and chief
          executive.</dd>
          <dt>Description:</dt>
          <dd>An authorization service for agent-initiated payments. It
          issues a verdict in the format of <xref target="format"/> for every
          evaluated request, in a test environment and a production
          environment.</dd>
          <dt>Issuer and keys:</dt>
          <dd>Issuer identifier https://verdicts.saifuro.com; JWK Set at
          https://verdicts.saifuro.com/.well-known/jwks.json, served through a
          content delivery network and holding one production key and one
          test key.</dd>
          <dt>Coverage:</dt>
          <dd>
            <xref target="format"/> and <xref target="keys"/>, with the
          departures from <xref target="RFC8725"/>, <xref target="RFC7493"/>,
          and <xref target="RFC8615"/> stated in this document.</dd>
          <dt>Version compatibility:</dt>
          <dd>This document (-00). Verdicts issued since 09:12 UTC on 9 October 2026 carry request.currency; verdicts issued before then may lack it, and all of them have expired.</dd>
          <dt>Implementation experience:</dt>
          <dd>Limits are enforced atomically (<xref target="sec-aggregate"/>).
          Approving a review repeats the checks described in
          <xref target="sec-review"/>. No key rotation has taken place yet. The
          event tokens of <xref target="sec-events"/> resemble Security Event
          Tokens <xref target="RFC8417"/> but do not follow that
          specification.</dd>
          <dt>Level of maturity:</dt>
          <dd>Early deployment; in service since September 2026. Issuing
          verdicts requires an account with Saifuro. Verifying them requires
          no account.</dd>
          <dt>Licensing:</dt>
          <dd>Proprietary service. Verification uses unmodified open-source
          JOSE libraries. The public documentation
          <xref target="SAIFURO-VERIFY"/> gives starting examples for jose
          (JavaScript), PyJWT (Python), and jwx (Go); they do not implement
          every step of <xref target="verify"/>, and the documentation lists the main checks they leave to the relying party.</dd>
          <dt>Documentation:</dt>
          <dd>
            <xref target="SAIFURO-VERIFY"/>,
          <xref target="SAIFURO-LIMITS"/>.</dd>
          <dt>Test vectors:</dt>
          <dd>
            <xref target="SAIFURO-VECTORS"/>: 138 tokens with their expected results, covering each step of <xref target="verify"/> and <xref target="stored"/>, signed with the example key of <xref target="example"/> and further published test keys.</dd>
          <dt>Contact:</dt>
          <dd>Ithelia Dias, ithelia.dias@saifuro.com.</dd>
          <dt>Last updated:</dt>
          <dd>9 October 2026.</dd>
        </dl>
      </section>
    </section>
    <section anchor="security">
      <name>Security Considerations</name>
      <t>The security considerations of <xref target="RFC7515"/>,
      <xref target="RFC7519"/>, and <xref target="RFC8725"/> apply.
      <xref target="I-D.ietf-oauth-rfc8725bis"/>, which would obsolete
      <xref target="RFC8725"/>, states that a typ value of "JWT" is not effective explicit typing (<xref target="I-D.ietf-oauth-rfc8725bis" section="3.11"/>) and extends the audience requirement to issuers that may issue JWTs for more than one relying party in the future (<xref target="I-D.ietf-oauth-rfc8725bis" section="3.9"/>); both widen the departures described in
      <xref target="sec-typ"/> and <xref target="sec-aud"/>.</t>
      <section anchor="sec-trust">
        <name>Trust in the Issuer and Its Key Set</name>
        <t>A verdict proves that the issuer made a statement, not that the
        statement is correct. An issuer that is compromised, misconfigured,
        or acting in bad faith can sign approvals for requests outside any
        mandate. How a relying party decides to accept an issuer is outside
        the scope of this document.</t>
        <t>The JWK Set is not signed. Whoever can change what is served at
        its configured location, including through control of the domain, its
        DNS, certificate issuance, or a TLS-terminating intermediary such as a
        content delivery network in front of the server, can add a key and
        mint verdicts that every verifier accepts. Protecting that endpoint is
        equivalent to protecting the signing keys. A copy of the JWK Set kept
        with stored verdicts (<xref target="rotation"/>) is the relying
        party's own record; it is not evidence to a third party that a key
        belonged to the issuer, because the deployed implementation neither
        signs its JWK Set nor publishes a history of retired keys.</t>
      </section>
      <section anchor="sec-operator">
        <name>Who Stands Behind a Verdict</name>
        <t>A verdict is evidence about one operator's policy, not about the
        payer. The token names no operator, and any operator that the issuer
        serves can configure a mandate that allows any recipient and amount,
        and then obtain a valid "allow" under it. A relying party that needs
        to know which operator stands behind a payment agrees the mandate
        identifiers with that operator out of band and accepts only verdicts
        whose mandate claim is one of them (<xref target="verify"/>, step 8).
        In the deployed implementation, mandate identifiers are assigned by
        the issuer and are not reused.</t>
        <t>The policy_version claim is the same on every verdict of one operator and is
        shared only with operators whose accounts were created on the same
        day. It links verdicts to an operator without reliably identifying
        one, and relying parties <bcp14>MUST NOT</bcp14> use it as an operator identifier.</t>
        <t>The member request.agent is unique only among one operator's agents in one environment, and in the deployed implementation it is "agt_" followed by a name the operator chooses, so any operator can obtain verdicts that name the same agent identifier as another operator. Relying parties <bcp14>MUST NOT</bcp14> use request.agent to identify an operator or a payer; step 8 of <xref target="verify"/> uses the mandate claim for that.</t>
      </section>
      <section anchor="sec-payee">
        <name>Payee Substitution</name>
        <t>Mandates in the deployed implementation do not restrict recipients.
        An agent that is compromised or misled, or anyone holding its
        credentials, can obtain an "allow" for a recipient of its choosing
        within the mandate's limits, and a relying party controlled by that
        recipient finds that every step of <xref target="verify"/> passes.
        Verdicts therefore do not defend against payee substitution; an
        operator that needs that defence applies its own controls to the
        recipients its agents request. Restricting recipients in mandates is
        an open issue (<xref target="open"/>).</t>
        <t>The issuer accepts as recipient (up to 1,024 characters) or category (up to 128) any non-empty string of Unicode characters other than noncharacters, including characters that render invisibly, reorder text, or resemble
        other characters, and an operator approving a review is shown the
        strings as the agent supplied them. An approval can therefore be
        obtained for a recipient that looks like another. Step 11 of
        <xref target="verify"/> does not help: it compares exactly, and the
        recipient that benefits is the one the token names.</t>
      </section>
      <section anchor="sec-bearer">
        <name>Bearer Tokens</name>
        <t>A verdict is a bearer token. It is not bound to a key held by the
        agent or the operator, it has no "cnf" claim <xref target="RFC7800"/>,
        and nothing in it identifies the party presenting it, the payer, or
        the order. Anyone who obtains an unused "allow" before it expires,
        such as the agent's runtime, an intermediary between the agent and the relying party, anyone who can read a log that recorded it, or a receiver of an event token that
        carries it (<xref target="sec-events"/>), can present it first, with
        a payment of the same amount and currency to the same recipient; the
        legitimate presentation then fails step 12 of
        <xref target="verify"/>. A relying party that releases goods,
        services, or funds on a verdict has to bind the order to the payer by
        its own means. Verdicts <bcp14>SHOULD</bcp14> be carried only over
        authenticated, confidential channels. Agents, operators, and relying parties <bcp14>SHOULD NOT</bcp14> log unexpired "allow" verdicts in full; jti or nonce identifies a verdict in a log without making it presentable. Proof of possession is an open issue (<xref target="open"/>).</t>
      </section>
      <section anchor="sec-alg">
        <name>Algorithms and Signatures</name>
        <t>Only ES256 is used and accepted. Verifiers pin it in configuration
        and reject "none", every HMAC algorithm, including when a public key
        is offered as the HMAC secret, and any spelling that differs in case
        (<xref target="RFC7515" section="4.1.1"/>,
        <xref target="RFC8725" section="2.1"/>,
        <xref target="RFC8725" section="3.1"/>). Every key in the set is
        published with "alg" "ES256".</t>
        <t><xref target="RFC8725" section="3.2"/> says that JWT libraries
        should implement ECDSA using the deterministic approach of
        <xref target="RFC6979"/>. The deployed issuer does not: it signs through OpenSSL 3.0, which derives the per-signature value from fresh random bytes mixed with the private key and the message digest. Its signatures are therefore not deterministic and do not reproduce the test vectors of <xref target="RFC6979"/>; the mixing is intended to keep a failure of the random number generator from exposing the key. Verifiers are unaffected: deterministic and
        randomized signatures verify identically.</t>
      </section>
      <section anchor="sec-typ">
        <name>Cross-JWT Confusion and Explicit Typing</name>
        <t>Verdicts and event tokens share the key, the issuer identifier,
        and the typ value "JWT", so <xref target="RFC8725" section="2.8"/>
        requires a mitigation. This format uses the second strategy listed in
        <xref target="RFC8725" section="3.12"/>, different required claims: a
        verdict requires exp, verdict, nonce, and request, which event tokens
        lack, and step 6 of <xref target="verify"/> rejects tokens that carry
        a type claim or an "evt_" jti. That step is the mutually exclusive
        validation rule that <xref target="RFC8725" section="3.12"/> requires
        for verdict verifiers; it rests on claims rather than on the header.
        Event receivers that require type and data, which verdicts lack,
        complete the mutual exclusion.</t>
        <t>The format does not use explicit typing, which
        <xref target="RFC8725" section="3.11"/> recommends for new kinds of
        JWT. With explicit typing, the distinction would rest on the header
        rather than on each verifier implementing step 6. Adopting it is an
        open issue (<xref target="open"/>).</t>
        <t>Test and production verdicts are the same kind of JWT from
        different environments, and differ only in the signing key. The only
        rule that excludes test verdicts is step 3 of
        <xref target="verify"/>, which reads a prefix of kid. JOSE leaves the
        structure of kid unspecified (<xref target="RFC7515" section="4.1.4"/>),
        so no generic JWT library applies this rule, and a relying party that
        omits step 3 accepts test verdicts. A verifier used only for testing does not reject production verdicts. A separate issuer identifier and
        JWK Set for test verdicts is an open issue (<xref target="open"/>).</t>
      </section>
      <section anchor="sec-aud">
        <name>Audience</name>
        <t>Verdicts have no "aud" claim. <xref target="RFC8725" section="3.9"/>
        requires one when an issuer issues JWTs intended for more than one
        relying party, which is the case here; this format does not meet that requirement. The same section requires a relying party to reject a JWT that has no audience value; a relying party that follows <xref target="verify"/> accepts verdicts without one, and so departs from that requirement as well. The member request.recipient is not an audience in the sense of
        <xref target="RFC7519" section="4.1.3"/>: it names the payee, which the
        agent chooses and the issuer does not check. When the relying party is
        the payee, step 11 of <xref target="verify"/> rejects a verdict
        presented for any other payee. When the relying party is an
        intermediary acting for the payee, such as a payment service provider
        or an escrow release process, nothing in the token names it, and two
        intermediaries settling for the same payee run separate nonce stores
        and could each accept the same verdict within its lifetime. A relying
        party <bcp14>SHOULD</bcp14> make sure that the identifier it compares
        against is specific to it and not shared with other parties. Adding an
        audience claim is an open issue (<xref target="open"/>).</t>
      </section>
      <section anchor="sec-replay">
        <name>Replay and Signature Malleability</name>
        <t>A verdict is valid for 300 seconds, and a relying party accepts its nonce only once (<xref target="verify"/>, step 12); relying parties that do not share a nonce store can each accept it (<xref target="sec-aud"/>).</t>
        <t>ECDSA signatures are malleable: if (R, S) is a valid signature, so
        is (R, n - S), where n is the order of the P-256 group. A verifier
        whose base64url decoder ignores unused trailing bits also accepts
        several spellings of the same signature segment. The same signed
        claims can therefore appear in more than one token string, and
        verifiers <bcp14>MUST NOT</bcp14> use the token string, or a hash of
        it, as the replay key.</t>
        <t>A verifier that recorded the nonce before comparing the verdict
        with its payment record would let anyone with a copy of a verdict
        burn it by presenting a mismatched payment; this is why step 12 comes
        last.</t>
        <t>The deployed implementation supports idempotent retries: an
        operator that retries an authorization request with the same
        Idempotency-Key, the same request body, and the same API credential
        within 24 hours receives the stored response, with the identical token
        and nonce, so a retry does not produce a second approval. A retry
        after 24 hours is a new evaluation with a new nonce, and each "allow"
        counts toward the mandate's rolling 30-day limit.</t>
      </section>
      <section anchor="sec-clock">
        <name>Clock Skew</name>
        <t>With a 300-second lifetime and a 60-second skew allowance, a
        verifier accepts a verdict until its own clock reads iat + 360, and
        rejects an iat more than 60 seconds ahead of its clock. Step 7 of <xref target="verify"/> assumes a synchronized clock.</t>
      </section>
      <section anchor="sec-keys">
        <name>Key Compromise</name>
        <t>There is no per-token revocation. The short lifetime of a verdict
        bounds the use of a stolen verdict, and removal from the JWK Set is
        the response to a stolen key. A verifier that refreshes on schedule
        stops trusting a removed key within the max-age of the set; one that
        pinned the key, or that keeps using a stale copy, keeps trusting it
        for as long as it does so. A party holding a compromised signing key
        can mint verdicts with current timestamps until the key is removed,
        and after a compromise, verdicts signed with that key, including those
        kept as records, can no longer be told apart from forgeries. How the
        issuer protects its signing keys is outside the scope of this
        document.</t>
        <t>A verifier that cannot obtain a key for a verdict
        <bcp14>MUST</bcp14> reject the verdict rather than accept it
        unverified.</t>
      </section>
      <section anchor="sec-parse">
        <name>Amounts and Parsing</name>
        <t>JSON leaves numeric range and precision to implementations, and
        <xref target="RFC8259" section="6"/> notes that good interoperability can be achieved by implementations that expect no more precision or range than binary64 provides; this is why amounts are compared by decimal
        value (<xref target="amounts"/>; <xref target="verify"/>, step 9).
        Step 1 of <xref target="verify"/> bounds the size of tokens; the deployed implementation limits recipient to 1,024 characters and category and currency to 128 characters each, so the verdicts it has issued since 09:12 UTC on 9 October 2026 are shorter than 11,000 characters. Its earlier verdicts could reach about 94,000 characters. Event tokens (<xref target="sec-events"/>) are not bounded in this way: an event token that carries a decision also carries that decision's verdict and is longer than it.</t>
      </section>
      <section anchor="sec-review">
        <name>Approval of Held Requests</name>
        <t>An "allow" that carries supersedes records an operator's approval
        of a request held for review. The format does not state whether the
        mandate was evaluated again at approval time, and nothing in the token
        prevents an issuer from issuing more than one "allow" that supersedes
        the same "review" verdict; such verdicts have different nonces, so the
        replay check in <xref target="verify"/> does not detect them. A
        relying party that must not settle against a revoked or expired
        mandate needs to learn of revocations from the operator. A relying party <bcp14>SHOULD</bcp14> record the supersedes value of each "allow" it accepts, keep it at least for the review expiry plus the verdict lifetime and skew allowance (24 hours and 360 seconds in the deployed implementation), and reject a second "allow" that supersedes the same verdict.</t>
        <t>In the deployed implementation, approving a review repeats three checks whose outcome can have changed since the review: that the agent is active, that the mandate is neither revoked nor expired, and that the amount, added to every "allow" issued under the mandate in the 30 days before the approval, is within the rolling 30-day limit. It does not repeat the frequency rule; the category and the per-transaction limit cannot have changed, because mandates are not edited. An approval that fails these checks
        is refused and issues no verdict, and a review yields at most one
        "allow". Any holder of an operator-wide credential can approve a
        review; the principal named on the mandate is recorded but not
        authenticated.</t>
      </section>
      <section anchor="sec-aggregate">
        <name>Aggregate Limits</name>
        <t>A verdict records the outcome of one evaluation. Whether an issuer
        enforces aggregate limits, such as the rolling 30-day limit and the
        frequency rule, across concurrent evaluations is a property of the
        issuer and is not visible in the token. The deployed implementation
        reads the limits and records each decision in a single database
        transaction.</t>
      </section>
      <section anchor="sec-events">
        <name>Event Tokens</name>
        <t>The deployed implementation notifies operators of events, such as
        a pending or resolved review, by webhook. Each event is a JWT with the
        same header, signed with the same key as the verdicts of its
        environment, under the same iss. Its claims are iss, jti (beginning
        "evt_"), iat, type, and data; it has no exp and no audience, and the issuer adds no claim that names the operator; only a "ping" event names the endpoint, by the webhook identifier in its data. A "decision.resolved" event carries, inside data, either the decision that approves a review, whose verdict member is "allow", together with that decision's verdict token, or the review object of a review that was denied or expired. A failed delivery is retried with the identical token; the last retry falls due 24 hours after the event is created.</t>
        <t>Because all operators' events in one environment are signed with
        the same key under the same iss, a genuine event issued to one
        operator also verifies at another operator's endpoint, at any later
        time: any operator served by the issuer can forward a
        "decision.resolved" event from its own endpoint, carrying an "allow"
        for a recipient it chose, to another operator's endpoint. Signature
        checks and deduplication on jti do not stop this. A receiver therefore confirms, through its own authenticated access to the issuer or against identifiers from its own responses, that an object named in an event is its own before acting on it, and bounds
        how old an event it accepts. A verdict verifier rejects event tokens
        by step 6 of <xref target="verify"/> and <bcp14>MUST NOT</bcp14>
        accept one as a verdict.</t>
      </section>
    </section>
    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>Verdicts are signed, not encrypted. Anyone who sees a token can read
      the agent identifier, which in the deployed implementation contains a
      name the operator chose for the agent; the amount, currency, recipient,
      and category; the mandate identifier; the time of the decision; and
      policy_version, which in the deployed implementation contains the date
      on which the operator's account was created.</t>
      <t>A token does not contain the operator's name or identifier, the end
      user's identity, payment credentials, the operator's metadata, or the
      reason text. The agent and mandate identifiers are stable across
      verdicts, and policy_version is the same for all of an operator's
      agents, so relying parties that compare the tokens they received can
      link payments made by the same agent, under the same mandate, or by
      different agents of the same operator.</t>
      <t>The token travels through the agent and any intermediary between
      the agent and the relying party. Operators <bcp14>SHOULD NOT</bcp14> put personal data in category, or in recipient beyond what identifies the payee; when the payee is a natural person, the recipient identifier is personal data and is visible to every party that handles the token. Relying parties
      <bcp14>SHOULD</bcp14> protect retained verdicts as they protect the
      payment records to which the verdicts relate.</t>
    </section>
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
      <t>A later version might request registration of the private claim
      names in <xref target="claims"/>, of a media type for explicit typing,
      and of a well-known URI suffix for the JWK Set
      (<xref target="open"/>).</t>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC3629" target="https://www.rfc-editor.org/info/rfc3629" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3629.xml">
          <front>
            <title>UTF-8, a transformation format of ISO 10646</title>
            <author fullname="F. Yergeau" initials="F." surname="Yergeau"/>
            <date month="November" year="2003"/>
            <abstract>
              <t>ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems. The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo. UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values. This memo obsoletes and replaces RFC 2279.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="63"/>
          <seriesInfo name="RFC" value="3629"/>
          <seriesInfo name="DOI" value="10.17487/RFC3629"/>
        </reference>
        <reference anchor="RFC7515" target="https://www.rfc-editor.org/info/rfc7515" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml">
          <front>
            <title>JSON Web Signature (JWS)</title>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <author fullname="J. Bradley" initials="J." surname="Bradley"/>
            <author fullname="N. Sakimura" initials="N." surname="Sakimura"/>
            <date month="May" year="2015"/>
            <abstract>
              <t>JSON Web Signature (JWS) represents content secured with digital signatures or Message Authentication Codes (MACs) using JSON-based data structures. Cryptographic algorithms and identifiers for use with this specification are described in the separate JSON Web Algorithms (JWA) specification and an IANA registry defined by that specification. Related encryption capabilities are described in the separate JSON Web Encryption (JWE) specification.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7515"/>
          <seriesInfo name="DOI" value="10.17487/RFC7515"/>
        </reference>
        <reference anchor="RFC7517" target="https://www.rfc-editor.org/info/rfc7517" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7517.xml">
          <front>
            <title>JSON Web Key (JWK)</title>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <date month="May" year="2015"/>
            <abstract>
              <t>A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. This specification also defines a JWK Set JSON data structure that represents a set of JWKs. Cryptographic algorithms and identifiers for use with this specification are described in the separate JSON Web Algorithms (JWA) specification and IANA registries established by that specification.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7517"/>
          <seriesInfo name="DOI" value="10.17487/RFC7517"/>
        </reference>
        <reference anchor="RFC7518" target="https://www.rfc-editor.org/info/rfc7518" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7518.xml">
          <front>
            <title>JSON Web Algorithms (JWA)</title>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <date month="May" year="2015"/>
            <abstract>
              <t>This specification registers cryptographic algorithms and identifiers to be used with the JSON Web Signature (JWS), JSON Web Encryption (JWE), and JSON Web Key (JWK) specifications. It defines several IANA registries for these identifiers.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7518"/>
          <seriesInfo name="DOI" value="10.17487/RFC7518"/>
        </reference>
        <reference anchor="RFC7519" target="https://www.rfc-editor.org/info/rfc7519" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7519.xml">
          <front>
            <title>JSON Web Token (JWT)</title>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <author fullname="J. Bradley" initials="J." surname="Bradley"/>
            <author fullname="N. Sakimura" initials="N." surname="Sakimura"/>
            <date month="May" year="2015"/>
            <abstract>
              <t>JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7519"/>
          <seriesInfo name="DOI" value="10.17487/RFC7519"/>
        </reference>
        <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml">
          <front>
            <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
            <author fullname="T. Bray" initials="T." role="editor" surname="Bray"/>
            <date month="December" year="2017"/>
            <abstract>
              <t>JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format. It was derived from the ECMAScript Programming Language Standard. JSON defines a small set of formatting rules for the portable representation of structured data.</t>
              <t>This document removes inconsistencies with other specifications of JSON, repairs specification errors, and offers experience-based interoperability guidance.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
          <seriesInfo name="DOI" value="10.17487/RFC8259"/>
        </reference>
        <reference anchor="RFC8725" target="https://www.rfc-editor.org/info/rfc8725" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8725.xml">
          <front>
            <title>JSON Web Token Best Current Practices</title>
            <author fullname="Y. Sheffer" initials="Y." surname="Sheffer"/>
            <author fullname="D. Hardt" initials="D." surname="Hardt"/>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <date month="February" year="2020"/>
            <abstract>
              <t>JSON Web Tokens, also known as JWTs, are URL-safe JSON-based security tokens that contain a set of claims that can be signed and/or encrypted. JWTs are being widely used and deployed as a simple security token format in numerous protocols and applications, both in the area of digital identity and in other application areas. This Best Current Practices document updates RFC 7519 to provide actionable guidance leading to secure implementation and deployment of JWTs.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="225"/>
          <seriesInfo name="RFC" value="8725"/>
          <seriesInfo name="DOI" value="10.17487/RFC8725"/>
        </reference>
        <reference anchor="SEC1" target="https://www.secg.org/sec1-v2.pdf">
          <front>
            <title>SEC 1: Elliptic Curve Cryptography</title>
            <author>
              <organization>Certicom Research</organization>
            </author>
            <date year="2009" month="May"/>
          </front>
          <refcontent>Standards for Efficient Cryptography, Version 2.0</refcontent>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="RFC2606" target="https://www.rfc-editor.org/info/rfc2606" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2606.xml">
          <front>
            <title>Reserved Top Level DNS Names</title>
            <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
            <author fullname="A. Panitz" initials="A." surname="Panitz"/>
            <date month="June" year="1999"/>
            <abstract>
              <t>To reduce the likelihood of conflict and confusion, a few top level domain names are reserved for use in private testing, as examples in documentation, and the like. In addition, a few second level domain names reserved for use as examples are documented. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="32"/>
          <seriesInfo name="RFC" value="2606"/>
          <seriesInfo name="DOI" value="10.17487/RFC2606"/>
        </reference>
        <reference anchor="RFC6979" target="https://www.rfc-editor.org/info/rfc6979" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6979.xml">
          <front>
            <title>Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)</title>
            <author fullname="T. Pornin" initials="T." surname="Pornin"/>
            <date month="August" year="2013"/>
            <abstract>
              <t>This document defines a deterministic digital signature generation procedure. Such signatures are compatible with standard Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) digital signatures and can be processed with unmodified verifiers, which need not be aware of the procedure described therein. Deterministic signatures retain the cryptographic security features associated with digital signatures but can be more easily implemented in various environments, since they do not need access to a source of high-quality randomness.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="6979"/>
          <seriesInfo name="DOI" value="10.17487/RFC6979"/>
        </reference>
        <reference anchor="RFC7493" target="https://www.rfc-editor.org/info/rfc7493" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7493.xml">
          <front>
            <title>The I-JSON Message Format</title>
            <author fullname="T. Bray" initials="T." role="editor" surname="Bray"/>
            <date month="March" year="2015"/>
            <abstract>
              <t>I-JSON (short for "Internet JSON") is a restricted profile of JSON designed to maximize interoperability and increase confidence that software can process it successfully with predictable results.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7493"/>
          <seriesInfo name="DOI" value="10.17487/RFC7493"/>
        </reference>
        <reference anchor="RFC7800" target="https://www.rfc-editor.org/info/rfc7800" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7800.xml">
          <front>
            <title>Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs)</title>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <author fullname="J. Bradley" initials="J." surname="Bradley"/>
            <author fullname="H. Tschofenig" initials="H." surname="Tschofenig"/>
            <date month="April" year="2016"/>
            <abstract>
              <t>This specification describes how to declare in a JSON Web Token (JWT) that the presenter of the JWT possesses a particular proof-of- possession key and how the recipient can cryptographically confirm proof of possession of the key by the presenter. Being able to prove possession of a key is also sometimes described as the presenter being a holder-of-key.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7800"/>
          <seriesInfo name="DOI" value="10.17487/RFC7800"/>
        </reference>
        <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7942.xml">
          <front>
            <title>Improving Awareness of Running Code: The Implementation Status Section</title>
            <author fullname="Y. Sheffer" initials="Y." surname="Sheffer"/>
            <author fullname="A. Farrel" initials="A." surname="Farrel"/>
            <date month="July" year="2016"/>
            <abstract>
              <t>This document describes a simple process that allows authors of Internet-Drafts to record the status of known implementations by including an Implementation Status section. 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.</t>
              <t>This process is not mandatory. Authors of Internet-Drafts are encouraged to consider using the process for their documents, and working groups are invited to think about applying the process to all of their protocol specifications. This document obsoletes RFC 6982, advancing it to a Best Current Practice.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="205"/>
          <seriesInfo name="RFC" value="7942"/>
          <seriesInfo name="DOI" value="10.17487/RFC7942"/>
        </reference>
        <reference anchor="RFC8417" target="https://www.rfc-editor.org/info/rfc8417" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8417.xml">
          <front>
            <title>Security Event Token (SET)</title>
            <author fullname="P. Hunt" initials="P." role="editor" surname="Hunt"/>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <author fullname="W. Denniss" initials="W." surname="Denniss"/>
            <author fullname="M. Ansari" initials="M." surname="Ansari"/>
            <date month="July" year="2018"/>
            <abstract>
              <t>This specification defines the Security Event Token (SET) data structure. A SET describes statements of fact from the perspective of an issuer about a subject. These statements of fact represent an event that occurred directly to or about a security subject, for example, a statement about the issuance or revocation of a token on behalf of a subject. This specification is intended to enable representing security- and identity-related events. A SET is a JSON Web Token (JWT), which can be optionally signed and/or encrypted. SETs can be distributed via protocols such as HTTP.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8417"/>
          <seriesInfo name="DOI" value="10.17487/RFC8417"/>
        </reference>
        <reference anchor="RFC8615" target="https://www.rfc-editor.org/info/rfc8615" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8615.xml">
          <front>
            <title>Well-Known Uniform Resource Identifiers (URIs)</title>
            <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
            <date month="May" year="2019"/>
            <abstract>
              <t>This memo defines a path prefix for "well-known locations", "/.well-known/", in selected Uniform Resource Identifier (URI) schemes.</t>
              <t>In doing so, it obsoletes RFC 5785 and updates the URI schemes defined in RFC 7230 to reserve that space. It also updates RFC 7595 to track URI schemes that support well-known URIs in their registry.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8615"/>
          <seriesInfo name="DOI" value="10.17487/RFC8615"/>
        </reference>
        <reference anchor="RFC9111" target="https://www.rfc-editor.org/info/rfc9111" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9111.xml">
          <front>
            <title>HTTP Caching</title>
            <author fullname="R. Fielding" initials="R." role="editor" surname="Fielding"/>
            <author fullname="M. Nottingham" initials="M." role="editor" surname="Nottingham"/>
            <author fullname="J. Reschke" initials="J." role="editor" surname="Reschke"/>
            <date month="June" year="2022"/>
            <abstract>
              <t>The Hypertext Transfer Protocol (HTTP) is a stateless application-level protocol for distributed, collaborative, hypertext information systems. This document defines HTTP caches and the associated header fields that control cache behavior or indicate cacheable response messages.</t>
              <t>This document obsoletes RFC 7234.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="98"/>
          <seriesInfo name="RFC" value="9111"/>
          <seriesInfo name="DOI" value="10.17487/RFC9111"/>
        </reference>
        <reference anchor="RFC9396" target="https://www.rfc-editor.org/info/rfc9396" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9396.xml">
          <front>
            <title>OAuth 2.0 Rich Authorization Requests</title>
            <author fullname="T. Lodderstedt" initials="T." surname="Lodderstedt"/>
            <author fullname="J. Richer" initials="J." surname="Richer"/>
            <author fullname="B. Campbell" initials="B." surname="Campbell"/>
            <date month="May" year="2023"/>
            <abstract>
              <t>This document specifies a new parameter authorization_details that is used to carry fine-grained authorization data in OAuth messages.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9396"/>
          <seriesInfo name="DOI" value="10.17487/RFC9396"/>
        </reference>
        <reference anchor="RFC9421" target="https://www.rfc-editor.org/info/rfc9421" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9421.xml">
          <front>
            <title>HTTP Message Signatures</title>
            <author fullname="A. Backman" initials="A." role="editor" surname="Backman"/>
            <author fullname="J. Richer" initials="J." role="editor" surname="Richer"/>
            <author fullname="M. Sporny" initials="M." surname="Sporny"/>
            <date month="February" year="2024"/>
            <abstract>
              <t>This document describes a mechanism for creating, encoding, and verifying digital signatures or message authentication codes over components of an HTTP message. This mechanism supports use cases where the full HTTP message may not be known to the signer and where the message may be transformed (e.g., by intermediaries) before reaching the verifier. This document also describes a means for requesting that a signature be applied to a subsequent HTTP message in an ongoing HTTP exchange.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9421"/>
          <seriesInfo name="DOI" value="10.17487/RFC9421"/>
        </reference>
        <reference anchor="RFC9449" target="https://www.rfc-editor.org/info/rfc9449" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9449.xml">
          <front>
            <title>OAuth 2.0 Demonstrating Proof of Possession (DPoP)</title>
            <author fullname="D. Fett" initials="D." surname="Fett"/>
            <author fullname="B. Campbell" initials="B." surname="Campbell"/>
            <author fullname="J. Bradley" initials="J." surname="Bradley"/>
            <author fullname="T. Lodderstedt" initials="T." surname="Lodderstedt"/>
            <author fullname="M. Jones" initials="M." surname="Jones"/>
            <author fullname="D. Waite" initials="D." surname="Waite"/>
            <date month="September" year="2023"/>
            <abstract>
              <t>This document describes a mechanism for sender-constraining OAuth 2.0 tokens via a proof-of-possession mechanism on the application level. This mechanism allows for the detection of replay attacks with access and refresh tokens.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9449"/>
          <seriesInfo name="DOI" value="10.17487/RFC9449"/>
        </reference>
        <reference anchor="RFC9943" target="https://www.rfc-editor.org/info/rfc9943" xml:base="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9943.xml">
          <front>
            <title>An Architecture for Trustworthy and Transparent Digital Supply Chains</title>
            <author fullname="H. Birkholz" initials="H." surname="Birkholz"/>
            <author fullname="A. Delignat-Lavaud" initials="A." surname="Delignat-Lavaud"/>
            <author fullname="C. Fournet" initials="C." surname="Fournet"/>
            <author fullname="Y. Deshpande" initials="Y." surname="Deshpande"/>
            <author fullname="S. Lasker" initials="S." surname="Lasker"/>
            <date month="June" year="2026"/>
            <abstract>
              <t>Traceability in supply chains is a growing security concern. While Verifiable Data Structures (VDSs) have addressed specific issues, such as equivocation over digital certificates, they lack a universal architecture for all supply chains. This document defines such an architecture for single-issuer signed statement transparency. It ensures extensibility and interoperability between different transparency services as well as compliance with various auditing procedures and regulatory requirements.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9943"/>
          <seriesInfo name="DOI" value="10.17487/RFC9943"/>
        </reference>
        <reference anchor="I-D.ietf-oauth-rfc8725bis" target="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc8725bis-10" xml:base="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.draft-ietf-oauth-rfc8725bis-10.xml">
          <front>
            <title>JSON Web Token Best Current Practices</title>
            <author fullname="Yaron Sheffer" initials="Y." surname="Sheffer">
              <organization>Independent</organization>
            </author>
            <author fullname="Dick Hardt" initials="D." surname="Hardt"/>
            <author fullname="Michael B. Jones" initials="M. B." surname="Jones">
              <organization>Self-Issued Consulting</organization>
            </author>
            <date day="21" month="August" year="2026"/>
            <abstract>
              <t>JSON Web Tokens, also known as JWTs, are URL-safe JSON-based security tokens that contain a set of claims that can be signed and/or encrypted. JWTs are being widely used and deployed as a simple security token format in numerous protocols and applications, both in the area of digital identity and in other application areas. This Best Current Practices (BCP) specification updates RFC 7519 to provide actionable guidance leading to secure implementation and deployment of JWTs. This BCP specification furthermore obsoletes RFC 8725 to provide additional actionable guidance covering threats and attacks that have been discovered since RFC 8725 was published.</t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-oauth-rfc8725bis-10"/>
        </reference>
        <reference anchor="I-D.ietf-oauth-transaction-tokens" target="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-transaction-tokens-11" xml:base="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.draft-ietf-oauth-transaction-tokens-11.xml">
          <front>
            <title>Transaction Tokens</title>
            <author fullname="Atul Tulshibagwale" initials="A." surname="Tulshibagwale">
              <organization>CrowdStrike</organization>
            </author>
            <author fullname="George Fletcher" initials="G." surname="Fletcher">
              <organization>Practical Identity LLC</organization>
            </author>
            <author fullname="Pieter Kasselman" initials="P." surname="Kasselman">
              <organization>Defakto Security</organization>
            </author>
            <date day="30" month="July" year="2026"/>
            <abstract>
              <t>Transaction Tokens (Txn-Tokens) are designed to maintain and propagate user identity, workload identity and authorization context throughout the Call Chain within a trusted domain during the processing of external requests (e.g. such as API calls) or requests initiated internally within the Trust Domain. Txn-Tokens ensure that this context is preserved throughout the Call Chain thereby enhancing security and consistency in complex, multi-service architectures.</t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-oauth-transaction-tokens-11"/>
        </reference>
        <reference anchor="I-D.ietf-webbotauth-httpsig-protocol" target="https://datatracker.ietf.org/doc/html/draft-ietf-webbotauth-httpsig-protocol-00" xml:base="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.draft-ietf-webbotauth-httpsig-protocol-00.xml">
          <front>
            <title>HTTP Message Signatures for automated traffic</title>
            <author fullname="Thibault Meunier" initials="T." surname="Meunier">
              <organization>Cloudflare</organization>
            </author>
            <author fullname="Sandor Major" initials="S." surname="Major">
              <organization>Google</organization>
            </author>
            <date day="1" month="September" year="2026"/>
            <abstract>
              <t>This document describes a protocol for identifying automated traffic using [HTTP-MESSAGE-SIGNATURES]. The goal is to allow automated HTTP clients to cryptographically sign outbound requests, allowing HTTP servers to verify their identity with confidence. It defines the Signature-Agent header field for in-band key discovery, a key directory format based on JWKS, and a well-known URI at which that directory is served.</t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-webbotauth-httpsig-protocol-00"/>
        </reference>
        <reference anchor="I-D.kuehlewind-audit-architecture" target="https://datatracker.ietf.org/doc/html/draft-kuehlewind-audit-architecture-01" xml:base="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.draft-kuehlewind-audit-architecture-01.xml">
          <front>
            <title>An Architecture for Auditing Agent Delegation and Interactions</title>
            <author fullname="Mirja Kühlewind" initials="M." surname="Kühlewind">
              <organization>Ericsson</organization>
            </author>
            <author fullname="Henk Birkholz" initials="H." surname="Birkholz">
              <organization>Fraunhofer SIT</organization>
            </author>
            <date day="7" month="September" year="2026"/>
            <abstract>
              <t>This document describes an architecture for auditing of agent-driven interactions on the Internet. Autonomous and semi-autonomous software agents, including those based on artificial intelligence, increasingly act on behalf of users, organizations, and services. Existing auditing mechanisms often capture isolated system events but do not consistently represent delegation relationships, user intent, or evolving authorization. In agent-driven systems, auditability requires linking intent, delegation, authorization, and execution. The proposed architecture enables this through distributed audit record generation, propagation of audit context, optional attestation, and additional logging for transparency.</t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-kuehlewind-audit-architecture-01"/>
        </reference>
        <reference anchor="I-D.laxsharma-pact" target="https://datatracker.ietf.org/doc/html/draft-laxsharma-pact-02" xml:base="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.draft-laxsharma-pact-02.xml">
          <front>
            <title>PACT: Co-Signed Task Contracts, Delivery and Verdict Records, and Outcome Records for Autonomous Agents</title>
            <author fullname="Laxmikant Sharma" initials="L." surname="Sharma">
              <organization>Independent</organization>
            </author>
            <date day="17" month="September" year="2026"/>
            <abstract>
              <t>Autonomous agents can already prove who they are, show whose authority they act under, find and call one another, and pay. What no existing specification lets them do is agree on a task in a form a third party can check, deliver against it, have the delivery judged by someone other than the performer, and carry away a record of the outcome that a stranger can verify. This document specifies PACT, a set of signed JSON records that closes that gap. PACT defines four things: a co-signed task contract whose digest covers its signature set; a Verdict record bound by digest to the Delivery it judges; a Facilitator-signed event trace and Outcome Record for every contract, recorded once, in one order, by a party other than the performer; and a Merkle commitment from a parent's Outcome Record to its subcontracts' Outcome Records. Settlement terms are carried by reference to a profile defined outside this document. This document specifies no escrow, custody or release of value, and takes no position on the legal effect of any record it defines.</t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-laxsharma-pact-02"/>
        </reference>
        <reference anchor="PSYCHIC" target="https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/">
          <front>
            <title>CVE-2022-21449: Psychic Signatures in Java</title>
            <author initials="N." surname="Madden"/>
            <date year="2022" month="April" day="19"/>
          </front>
        </reference>
        <reference anchor="OIDC-CORE" target="https://openid.net/specs/openid-connect-core-1_0.html">
          <front>
            <title>OpenID Connect Core 1.0 incorporating errata set 2</title>
            <author initials="N." surname="Sakimura"/>
            <author initials="J." surname="Bradley"/>
            <author initials="M." surname="Jones"/>
            <author initials="B." surname="de Medeiros"/>
            <author initials="C." surname="Mortimore"/>
            <date year="2023" month="December"/>
          </front>
          <refcontent>OpenID Foundation</refcontent>
        </reference>
        <reference anchor="AUTHZEN" target="https://openid.net/specs/authorization-api-1_0.html">
          <front>
            <title>Authorization API 1.0</title>
            <author initials="O." surname="Gazitt" role="editor"/>
            <author initials="D." surname="Brossard" role="editor"/>
            <author initials="A." surname="Tulshibagwale" role="editor"/>
            <date year="2026" month="January" day="11"/>
          </front>
          <refcontent>OpenID Foundation Final Specification</refcontent>
        </reference>
        <reference anchor="AP2" target="https://ap2-protocol.org/ap2/specification/">
          <front>
            <title>Agent Payments Protocol (AP2) Specification, version 0.2</title>
            <author>
              <organization>Google</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 7 October 2026</refcontent>
        </reference>
        <reference anchor="ACP" target="https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/blob/17adf494cf8b4bcb41967a0386188b8103316d2f/spec/2026-04-17/openapi/openapi.delegate_payment.yaml">
          <front>
            <title>Agentic Commerce Protocol: Delegate Payment API, version 2026-04-17</title>
            <author>
              <organization>OpenAI</organization>
            </author>
            <author>
              <organization>Stripe</organization>
            </author>
            <date year="2026" month="April"/>
          </front>
        </reference>
        <reference anchor="X402" target="https://github.com/x402-foundation/x402/blob/e187dda1ef0c69c85416625342e5bb7c4b857dac/specs/x402-specification-v2.md">
          <front>
            <title>x402 Protocol Specification, Protocol Version 2</title>
            <author>
              <organization>x402 Foundation</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 7 October 2026</refcontent>
        </reference>
        <reference anchor="TAP" target="https://developer.visa.com/capabilities/trusted-agent-protocol/trusted-agent-protocol-specifications">
          <front>
            <title>Trusted Agent Protocol Specifications</title>
            <author>
              <organization>Visa</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 7 October 2026</refcontent>
        </reference>
        <reference anchor="AUDIT" target="https://mailarchive.ietf.org/arch/browse/audit/">
          <front>
            <title>audit: discussion of a potential Agent Use of Delegation and Interaction Traceability (AUDIT) BoF</title>
            <author>
              <organization>IETF</organization>
            </author>
            <date/>
          </front>
        </reference>
        <reference anchor="SAIFURO-VERIFY" target="https://docs.saifuro.com/reference/verify-a-verdict">
          <front>
            <title>Verifying a verdict</title>
            <author>
              <organization>Saifuro LLC</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 9 October 2026</refcontent>
        </reference>
        <reference anchor="SAIFURO-LIMITS" target="https://docs.saifuro.com/reference/verdict-limits">
          <front>
            <title>Limits of a signed verdict</title>
            <author>
              <organization>Saifuro LLC</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 9 October 2026</refcontent>
        </reference>
        <reference anchor="SAIFURO-VECTORS" target="https://docs.saifuro.com/reference/verdict-test-vectors">
          <front>
            <title>Verdict test vectors</title>
            <author>
              <organization>Saifuro LLC</organization>
            </author>
            <date/>
          </front>
          <refcontent>accessed 9 October 2026</refcontent>
        </reference>
      </references>
    </references>
    <section anchor="example">
      <name>Example</name>
      <t>This appendix contains a verdict signed with an example key. The
      private key is published here so that anyone can reproduce and extend
      the example. It is not a key of any issuer, a token signed with it
      proves nothing, and it <bcp14>MUST NOT</bcp14> be added to a verifier
      that protects real payments. The issuer identifier is a reserved example
      domain <xref target="RFC2606"/>.</t>
      <section anchor="example-key">
        <name>Example Key</name>
        <sourcecode type="json">
{
  "kty": "EC",
  "crv": "P-256",
  "x": "50tYIab3ytEcPnb_fuZCPc4cM87aNhpYhOYb9LmSseA",
  "y": "iZho4NBfqRZnM7AgedlHkvEMRU030NPOYGoTv7s2Ls0",
  "d": "34KI9Rx04_gEp_Ljm4-dGFq7O75vEFednnvRwcDdvUc",
  "use": "sig",
  "alg": "ES256",
  "kid": "example-1"
}
</sourcecode>
      </section>
      <section anchor="example-token">
        <name>Verdict</name>
        <t>The token, with line breaks for display purposes only:</t>
        <artwork align="left"><![CDATA[
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImV4YW1wbGUtMSJ9.eyJ
pc3MiOiJodHRwczovL2lzc3Vlci5leGFtcGxlIiwianRpIjoiZGVjXzViMmU5YzQ
xIiwiaWF0IjoxNzkxMzc0NDAwLCJleHAiOjE3OTEzNzQ3MDAsInZlcmRpY3QiOiJ
hbGxvdyIsIm1hbmRhdGUiOiJtbmRfN2YzYTBkMTIiLCJwb2xpY3lfdmVyc2lvbiI
6InBvbF8yMDI2LTA5LTAyLjEiLCJub25jZSI6Im5fOWQwMmM2ZTQxYTdmM2I4NSI
sInJlcXVlc3QiOnsiYWdlbnQiOiJhZ3RfcHJvY3VyZW1lbnRfMDEiLCJhbW91bnQ
iOjM0MCwiY3VycmVuY3kiOiJVU0QiLCJyZWNpcGllbnQiOiJ2ZW5kb3I6YWNtZV9
zYWFzIiwiY2F0ZWdvcnkiOiJzYWFzIn19.5NLM85wfRPdBIBaW_fY_gmgfml5w-0
KZlVbDj0YUVxa03wiYmqXamfLynH_S_DUkk2j_HTAlorcS3tHdtNvwYA
]]></artwork>
        <t>Decoded JOSE Header:</t>
        <sourcecode type="json">
{"alg":"ES256","typ":"JWT","kid":"example-1"}
</sourcecode>
        <t>Decoded claims, with whitespace added:</t>
        <sourcecode type="json">
{
  "iss": "https://issuer.example",
  "jti": "dec_5b2e9c41",
  "iat": 1791374400,
  "exp": 1791374700,
  "verdict": "allow",
  "mandate": "mnd_7f3a0d12",
  "policy_version": "pol_2026-09-02.1",
  "nonce": "n_9d02c6e41a7f3b85",
  "request": {
    "agent": "agt_procurement_01",
    "amount": 340,
    "currency": "USD",
    "recipient": "vendor:acme_saas",
    "category": "saas"
  }
}
</sourcecode>
      </section>
      <section anchor="example-check">
        <name>Checking the Example</name>
        <t>The verdict was issued at 2026-10-07T12:00:00Z and expired at
        12:05:00Z. A verifier configured with the example key, the issuer
        identifier https://issuer.example, and a payment record of 340.00 USD
        to "vendor:acme_saas", with its clock pinned to 2026-10-07T12:02:00Z
        (Unix time 1791374520), accepts it; for step 8, the mandate identifier agreed with the operator is "mnd_7f3a0d12" and the agreed unit is major units (US dollars). With the clock
        unpinned, it rejects the token at step 7 of <xref target="verify"/>,
        as intended. A production verifier never pins its clock.</t>
        <t>The S component of the example signature is in the upper half of
        the group order, so a verifier that enforces low-S signatures,
        contrary to step 5, rejects this example.</t>
      </section>
    </section>
    <section anchor="open">
      <name>Open Issues</name>
      <ol spacing="normal">
        <li>Explicit typing. Use a dedicated typ value for verdicts, such as
        "verdict+jwt", as <xref target="RFC8725" section="3.11"/> recommends,
        and register the corresponding media type.</li>
        <li>Audience. Add an "aud" claim naming the relying party or the
        settlement endpoint, so that the format meets
        <xref target="RFC8725" section="3.9"/>, and define how the agent
        learns the value before evaluation.</li>
        <li>Proof of possession. Bind a verdict to a key held by the agent,
        for example with a confirmation claim <xref target="RFC7800"/>, so
        that a copy cannot be used by another presenter.</li>
        <li>Environment separation. Use a separate issuer identifier and JWK
        Set for test verdicts, instead of a kid prefix.</li>
        <li>Operator binding. Decide whether a verdict should identify the
        operator, and how a relying party would use that identifier.</li>
        <li>Recipient restrictions. Let a mandate restrict the recipients for
        which an "allow" can be issued.</li>
        <li>Policy identification. Remove policy_version, or make it, or a new
        claim such as a digest of the mandate as evaluated, identify the rules
        that were applied.</li>
        <li>Claim names. Register the private claims in the "JSON Web Token
        Claims" registry, or use collision-resistant names.</li>
        <li>Replay identifier. jti is the unique token identifier of <xref target="RFC7519" section="4.1.7"/>, which notes that it can be used to prevent replay; the separate nonce claim could be removed.</li>
        <li>Amount representation. Choose between JSON numbers in a
        constrained decimal form, decimal strings as
        <xref target="RFC7493"/> recommends, and integers in minor units.</li>
        <li>Asset codes. Define identifiers for assets that have no ISO 4217
        code.</li>
        <li>Enforcement mode. Decide whether a verdict should state whether
        the issuing environment was enforcing.</li>
        <li>Event tokens. Profile event tokens as Security Event Tokens
        <xref target="RFC8417"/>, with typ "secevent+jwt", an "events"
        claim, and an "aud" naming the operator's endpoint.
        <xref target="RFC8417"/> recommends against exp in such tokens, and
        the absence of exp is one of the properties that makes an event token
        fail step 6 of <xref target="verify"/>.</li>
        <li>Deterministic signatures. Sign with <xref target="RFC6979"/>.</li>
        <li>Key set integrity. Sign the JWK Set or publish a history of
        retired keys, for example through a transparency service
        <xref target="RFC9943"/>, so that stored verdicts remain verifiable to
        third parties.</li>
        <li>Amount unit. State the unit of request.amount in the token, or fix it, so that a relying party does not need to agree it out of band (<xref target="amounts"/>).</li>
        <li>JWK Set location. Register a well-known URI suffix for the JWK Set (<xref target="RFC8615" section="3"/>), or let relying parties take the location from issuer metadata, instead of the unregistered "jwks.json".</li>
        <li>Revocation status. Decide whether relying parties need a way to learn that a mandate was revoked after an "allow" was issued (<xref target="asserts"/>).</li>
        <li>Transport. Define how a verdict accompanies a payment in HTTP and
        in agent payment protocols such as <xref target="X402"/>,
        <xref target="ACP"/>, and <xref target="AP2"/>.</li>
        <li>Related formats. Determine whether a verdict can be expressed as a
        signed form of an <xref target="AUTHZEN"/> evaluation response, or its
        request claim as an "authorization_details" object
        (<xref target="RFC9396"/>, which registers that claim in
        Section 14.2) of a payment type.</li>
      </ol>
    </section>
    <section anchor="ack" numbered="false">
      <name>Acknowledgments</name>
      <t>The author thanks Nicholas Templeman, whose messages on the audit
      mailing list <xref target="AUDIT"/> set out the distinction between an
      unsupported association and a contradicted one, which
      <xref target="outcomes"/> adopts, and the binding problem that <xref target="sec-aud"/> describes.</t>
      <t>The author also thanks Nancy Sahu and Gareth Wong, whose proposal on the same list, that the charter state, for each verification mechanism, what a successful check establishes, under what assumptions, and whether an omitted record would be detectable, poses the question that <xref target="asserts"/> answers for this format.</t>
      <t>The text of this document was drafted with an AI system (Claude, by
      Anthropic) from the implementation's source code and documentation and
      from the cited specifications, and was checked against them in further
      AI-assisted reviews. The author has reviewed the whole document and is
      responsible for its content.</t>
    </section>
  </back>
</rfc>
