<?xml version='1.0' encoding='utf-8'?>
<rfc version="3" ipr="trust200902" category="std" submissionType="IETF" docName="draft-senarath-a2wp-00" tocInclude="true" tocDepth="3" symRefs="true" sortRefs="true" consensus="true">
  <front>
    <title abbrev="A2WP">Agent-to-Wallet Protocol for Digital Credentials (A2WP)</title>
    <author fullname="Thilina Shashimal Senarath" initials="T. S." surname="Senarath">
      <address>
        <email>thilinasenarath97@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="September" day="19"/>
    <workgroup>Network Working Group</workgroup>
    <keyword>digital credentials</keyword>
    <keyword>AI agents</keyword>
    <keyword>wallet</keyword>
    <keyword>A2WP</keyword>
    <keyword>OpenID4VCI</keyword>
    <keyword>OpenID4VP</keyword>
    <abstract>
      <t>This document defines the Agent-to-Wallet Protocol (A2WP), an interface through which a software Agent requests digital credential operations from a Wallet. A2WP supports credential acquisition, presentation, and optional queries for authorized credential metadata. The Wallet controls credential selection, disclosure, approval, and cryptographic execution.</t>
      <t>A2WP defines an information model, observable operation behavior, and an HTTPS binding. Credential formats, Agent identity schemes, delegation mechanisms, policy languages, and Wallet internals are outside its scope. External credential protocols are integrated through protocol mappings.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="introduction">
      <name>Introduction</name>
      <t>An Agent carrying out a task can encounter a credential offer or a request to prove an attribute. A2WP provides a common interface for asking a Wallet to process that interaction. The Agent expresses credential intent; the Wallet exercises credential authority.</t>
      <t>This separation is useful when an Agent processes untrusted instructions or content. The Wallet independently decides whether the requested operation is permitted and executes the applicable credential protocol. Credentials and presentations need not enter the Agent's model context.</t>
      <artwork type="ascii-art"><![CDATA[Agent -- A2WP --> Wallet -- Issuance --> Issuer
                    |
                    +---- Presentation --> Verifier]]></artwork>
      <t>An Agent may act for a person, organization, or service. It need not be the credential subject or Holder. A2WP can also be used by software clients that do not use a language model.</t>
      <section anchor="scope">
        <name>Scope</name>
        <t>This specification standardizes the messages exchanged between an Agent and a Wallet and the outcomes visible to the Agent. Wallet architecture, storage, internal state management, policy evaluation, credential selection algorithms, approval workflows, and user interfaces are implementation concerns.</t>
        <t>A2WP does not define how authority is delegated to an Agent, how a remote service authorizes a business transaction, or how a credential proves the identity of an Agent. It provides no private-key export, credential export, or general-purpose signing operation.</t>
        <t>The information model is independent of transport. This document defines an HTTPS binding and two external-protocol mappings. Other bindings and mappings can be defined separately. Their requirements do not extend to implementations that do not support them.</t>
      </section>
    </section>
    <section anchor="terminology">
      <name>Conventions and Terminology</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/>
        <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
      <dl newline="true" spacing="compact">
        <dt>Agent</dt>
        <dd>
          <t>Software acting as an A2WP client, including an Agent runtime or orchestrator.</t>
        </dd>
        <dt>Principal</dt>
        <dd>
          <t>The person, organization, service, or other entity whose authority applies to an operation. Establishing the Agent's relationship to a Principal is outside this specification.</t>
        </dd>
        <dt>Wallet</dt>
        <dd>
          <t>The A2WP service responsible for credential operations and their authorization. It may use other trusted components to perform its functions.</t>
        </dd>
        <dt>Credential</dt>
        <dd>
          <t>A cryptographically protected set of claims issued by an Issuer.</t>
        </dd>
        <dt>Holder, Issuer, and Verifier</dt>
        <dd>
          <t>The Holder is the entity on whose behalf credentials are held and presented. The Issuer issues credentials; the Verifier requests or evaluates presentations. The Holder need not be the credential subject.</t>
        </dd>
        <dt>Credential Handle</dt>
        <dd>
          <t>An opaque Wallet-generated reference to a credential. Possession of a handle grants no authority.</t>
        </dd>
        <dt>Operation</dt>
        <dd>
          <t>A Wallet-managed acquisition or presentation with an identifier and observable status. It may finish immediately or asynchronously.</t>
        </dd>
        <dt>Protocol Mapping</dt>
        <dd>
          <t>A specification associating a protocol identifier with allowed operations, request data, and completion semantics.</t>
        </dd>
      </dl>
    </section>
    <section anchor="model">
      <name>Interaction Model</name>
      <t>The Agent submits a credential request. The Wallet determines the applicable authorization, selects permitted credentials or issuance options, obtains any required approval, and performs the external protocol. The Agent can retrieve the resulting operation state and request cancellation. These steps do not prescribe the Wallet's internal workflow.</t>
      <t>The Wallet MUST authorize credential queries, operation creation, status retrieval, and cancellation in the applicable authenticated Agent and Principal context. The mechanism establishing this context is deployment-specific. An Agent-supplied identifier or purpose statement MUST NOT by itself establish authority.</t>
      <t>The Agent and Wallet are separate trust domains even when deployed together. The Wallet MUST retain control of credential private keys and MUST NOT return those keys, complete credentials, or presentations in A2WP responses. These restrictions also apply to extension fields and error details.</t>
      <section anchor="conformance">
        <name>Supported Capabilities</name>
        <t>A conforming Wallet MUST support at least one of <tt>acquire</tt> or <tt>present</tt> with a defined protocol mapping, and MUST support operation creation and status retrieval. Credential query is OPTIONAL. A Wallet MUST expose its supported operations and mappings through the metadata in <xref target="metadata"/> or equivalent trusted deployment configuration. The Agent MUST use a supported operation and mapping combination.</t>
        <t>The mappings in <xref target="mappings"/> define the combinations used by this document. Supporting the A2WP core does not require supporting both mappings. Cancellation requests have the behavior in <xref target="cancellation"/>; a Wallet can reject cancellation when it cannot safely stop an operation.</t>
      </section>
    </section>
    <section anchor="information-model">
      <name>Information Model</name>
      <t>Messages are JSON objects <xref target="RFC8259"/>. Member names and identifier values are case-sensitive. Required members MUST be present and have the specified types; explicit <tt>null</tt> does not substitute for an omitted optional member. Duplicate member names MUST be rejected. Timestamp fields defined here are strings in the date-time format of <xref target="RFC3339"/>.</t>
      <section anchor="operation-request">
        <name>Operation Request</name>
        <dl newline="true" spacing="compact">
          <dt>
            <tt>operation</tt>
          </dt>
          <dd>
            <t>REQUIRED string: <tt>acquire</tt>, <tt>present</tt>, or an operation identifier defined by an agreed extension.</t>
          </dd>
          <dt>
            <tt>protocol</tt>
          </dt>
          <dd>
            <t>REQUIRED string identifying the applicable protocol mapping.</t>
          </dd>
          <dt>
            <tt>request</tt>
          </dt>
          <dd>
            <t>REQUIRED object whose contents are defined by the mapping.</t>
          </dd>
          <dt>
            <tt>context</tt>
          </dt>
          <dd>
            <t>OPTIONAL object containing advisory application context. Its properties are deployment-specific; <tt>task_id</tt> and <tt>purpose</tt> in the examples are illustrative, not standardized authorization attributes.</t>
          </dd>
        </dl>
        <t>The Wallet MUST treat Agent-supplied context as untrusted. It MAY use such information for explanation, correlation, or auditing subject to policy. The presence or absence of context MUST NOT replace authorization.</t>
      </section>
      <section anchor="operation-representation">
        <name>Operation Representation</name>
        <dl newline="true" spacing="compact">
          <dt>
            <tt>operation_id</tt>
          </dt>
          <dd>
            <t>REQUIRED opaque string identifying the operation within the Wallet.</t>
          </dd>
          <dt>
            <tt>operation</tt> and <tt>protocol</tt>
          </dt>
          <dd>
            <t>REQUIRED strings identifying the accepted operation and mapping.</t>
          </dd>
          <dt>
            <tt>status</tt>
          </dt>
          <dd>
            <t>REQUIRED string with a value defined in <xref target="lifecycle"/>.</t>
          </dd>
          <dt>
            <tt>status_uri</tt>
          </dt>
          <dd>
            <t>REQUIRED in the HTTPS binding: an absolute HTTPS URI for retrieving the operation. Other bindings define their own retrieval mechanism.</t>
          </dd>
          <dt>
            <tt>interaction</tt>
          </dt>
          <dd>
            <t>OPTIONAL object describing a required interaction; permitted only while <tt>status</tt> is <tt>interaction_required</tt>.</t>
          </dd>
          <dt>
            <tt>result</tt>
          </dt>
          <dd>
            <t>OPTIONAL object containing authorized result information defined by the mapping; permitted only when <tt>status</tt> is <tt>completed</tt>.</t>
          </dd>
          <dt>
            <tt>error</tt>
          </dt>
          <dd>
            <t>REQUIRED when <tt>status</tt> is <tt>failed</tt>, otherwise absent. An error object as defined in <xref target="errors"/>.</t>
          </dd>
          <dt>
            <tt>completed_at</tt>
          </dt>
          <dd>
            <t>OPTIONAL timestamp indicating when the operation entered a terminal state.</t>
          </dd>
          <dt>
            <tt>expires_at</tt>
          </dt>
          <dd>
            <t>OPTIONAL timestamp after which the Wallet will no longer attempt to complete a nonterminal operation. It does not specify how long its status remains retrievable.</t>
          </dd>
        </dl>
        <t>The operation identifier, operation type, and mapping MUST remain unchanged during the operation's lifetime. A status response describes the Wallet's current view; an Agent may observe only some intermediate states. A Wallet MUST apply disclosure policy to every representation, including results and errors.</t>
      </section>
      <section anchor="interaction">
        <name>Interaction</name>
        <t>An interaction object contains an OPTIONAL <tt>interaction_uri</tt> string and an OPTIONAL <tt>expires_at</tt> timestamp. The URI identifies a Wallet-authorized interaction entry point for an appropriate actor or application. Additional interaction properties are deployment-specific.</t>
        <t>The Wallet arranges the approval or other interaction. If no URI is returned, the Agent can continue polling while the interaction occurs through another channel. The Agent MUST NOT assume that receiving a URI authorizes it to complete the interaction. A2WP does not standardize the interaction UI, its authentication mechanism, or a separate approval endpoint.</t>
      </section>
      <section anchor="credential-metadata">
        <name>Credential Metadata</name>
        <t>A Credential Metadata object contains a REQUIRED <tt>credential_handle</tt> string and an OPTIONAL <tt>properties</tt> object. Properties describe the credential using names and value semantics agreed by a deployment or profile. This specification does not define a cross-format credential taxonomy.</t>
        <t>Handles MUST be opaque and MUST NOT embed credential claims. Wallets SHOULD scope handles to the authorized Agent and Principal context to limit correlation. A handle is a reference for correlation; this base specification does not define Agent-directed credential selection by handle. A later query need not return the same handle.</t>
      </section>
    </section>
    <section anchor="operations">
      <name>Credential Operations</name>
      <section anchor="creation">
        <name>Creation and Retrieval</name>
        <t>The Wallet validates and authorizes an operation request before accepting it. An accepted request creates an operation and returns its representation. Acceptance does not imply that disclosure has been approved or that the external protocol has succeeded. The Agent retrieves subsequent representations using the mechanism defined by the binding; in the HTTPS binding, this is the returned status URI.</t>
        <t>An <tt>acquire</tt> operation asks the Wallet to obtain and retain credentials. A <tt>present</tt> operation asks the Wallet to respond to an external presentation request. The applicable mapping defines the request data and the completion point. The Wallet remains responsible for credential selection and disclosure.</t>
      </section>
      <section anchor="lifecycle">
        <name>Observable Status</name>
        <dl newline="true" spacing="compact">
          <dt>
            <tt>pending</tt>
          </dt>
          <dd>
            <t>Accepted and waiting to proceed, without a currently reported interaction requirement.</t>
          </dd>
          <dt>
            <tt>interaction_required</tt>
          </dt>
          <dd>
            <t>Waiting for an action outside the operation's automatic processing. The interaction mechanism remains under Wallet control.</t>
          </dd>
          <dt>
            <tt>processing</tt>
          </dt>
          <dd>
            <t>The Wallet is attempting to perform the operation.</t>
          </dd>
          <dt>
            <tt>completed</tt>
          </dt>
          <dd>
            <t>The completion conditions of the selected mapping have been met.</t>
          </dd>
          <dt>
            <tt>failed</tt>
          </dt>
          <dd>
            <t>The Wallet has stopped processing without establishing successful completion. Failure does not imply absence of external effects.</t>
          </dd>
          <dt>
            <tt>cancelled</tt>
          </dt>
          <dd>
            <t>The Wallet has stopped the operation with the guarantees in <xref target="cancellation"/>.</t>
          </dd>
        </dl>
        <t>The first three states are nonterminal. A Wallet MAY move among them as processing requires, or enter a terminal state. The last three states are terminal and MUST NOT transition to another state. An operation can be terminal in its first returned representation. These states describe externally observable behavior, not the Wallet's internal execution model.</t>
        <t>If an operation or interaction expires before completion, the Wallet MUST stop further processing and report <tt>failed</tt>. It uses the appropriate expiry code unless it cannot determine whether an external action succeeded, in which case it MUST use <tt>outcome-unknown</tt>. The same uncertainty rule applies to other failures. A timeout alone is not evidence that no disclosure or issuance occurred.</t>
        <t>Completion of presentation does not by itself establish that the Verifier accepted the claims, authorized a business transaction, or associated that transaction with the Agent. Those guarantees belong to the external protocol or application integration.</t>
      </section>
      <section anchor="cancellation">
        <name>Cancellation</name>
        <t>An Agent MAY request cancellation of any nonterminal operation. The Wallet MUST authorize the request and either return a <tt>cancelled</tt> representation or reject cancellation. It MUST NOT report cancellation if a presentation has already been submitted, an acquired credential has already been retained, or it cannot ensure that these actions have stopped. Rejected cancellation does not change the operation state.</t>
        <t>After reporting <tt>cancelled</tt>, the Wallet MUST NOT continue the requested acquisition or presentation. Cancellation does not undo earlier network interactions. Repeating cancellation of a cancelled operation returns its cancelled representation. A completed or failed operation cannot be cancelled. Operation status remains retrievable according to the Wallet's retention policy.</t>
      </section>
      <section anchor="retries">
        <name>Retries and Retention</name>
        <t>Operation creation is not idempotent in this base specification. If acceptance is uncertain after a connection failure, the Agent MUST NOT automatically repeat the request unless an agreed extension provides safe duplicate handling. Advisory context, including a task identifier, is not a deduplication mechanism.</t>
        <t>An Agent can retry status retrieval. Operation retention periods and internal recovery mechanisms are implementation concerns. After retention ends, the Wallet can report the operation as unavailable. An unavailable status MUST NOT be interpreted as proof that the operation did not execute.</t>
      </section>
    </section>
    <section anchor="query">
      <name>Optional Credential Query</name>
      <t>A query requests only metadata the Agent is permitted to discover. Query authorization is independent of acquisition or presentation authorization. A Wallet MUST NOT infer permission to disclose an inventory from permission to present a credential.</t>
      <t>The request is an object with OPTIONAL <tt>filter</tt> and <tt>cursor</tt> members. A filter is an object whose vocabulary and matching semantics are specified by a deployment or profile. A cursor is a string. A Wallet MUST reject a filter it does not support rather than silently broaden the query. With no filter, the request covers the metadata visible to the Agent under policy.</t>
      <t>The response contains a REQUIRED <tt>credentials</tt> array of Credential Metadata objects, which can be empty. If more results remain, it MUST include a <tt>next_cursor</tt> string. The Agent continues by sending that value as <tt>cursor</tt> with the same filter. Cursors are opaque, bound to the authorized query context, and do not grant access. Page size, cursor lifetime, ordering, and snapshot consistency are implementation concerns; unsupported or expired cursors produce <tt>invalid-request</tt>.</t>
      <t>The response is not a promise that any returned credential can satisfy a future presentation. Querying is not a prerequisite to requesting presentation. The examples below use an unfiltered query and no deployment-specific metadata properties.</t>
      <sourcecode type="json"><![CDATA[{}]]></sourcecode>
      <sourcecode type="json"><![CDATA[{
  "credentials": [
    {
      "credential_handle": "cred_d4R7vN2kL9pT5mQ8sH1c6A"
    }
  ]
}]]></sourcecode>
    </section>
    <section anchor="mappings">
      <name>External Protocol Mappings</name>
      <t>A protocol mapping defines its identifier, allowed operation types, request object, completion conditions, and any result members. It also identifies its supported external protocol variants. A Wallet MUST apply the external protocol's validation and security requirements; a mapping does not authorize bypassing them. Other mappings can be specified independently of the A2WP core.</t>
      <section anchor="openid4vci">
        <name>OpenID4VCI Acquisition</name>
        <t>The identifier <tt>openid4vci</tt> selects <tt>acquire</tt> using OpenID for Verifiable Credential Issuance 1.0 <xref target="OPENID4VCI"/>. The request MUST contain exactly one of <tt>credential_offer</tt>, an object containing a Credential Offer, or <tt>credential_offer_uri</tt>, an HTTPS URI string referencing an offer. Offer processing follows the external protocol.</t>
        <t>The Wallet chooses the permitted issuance options and handles authentication, transaction-code entry, and deferred issuance. Where an interaction is needed, it uses <tt>interaction_required</tt>. A deferred response does not complete acquisition. An unsupported offer or required protocol feature produces <tt>unsupported-protocol</tt>.</t>
        <t>The operation completes when the Wallet has obtained, validated as required by the external protocol and its policy, and stored all credentials it undertook to acquire. A partial acquisition MUST NOT be reported as completed. If multiple credentials are involved, failure does not imply that already stored credentials were rolled back. Authorized metadata MAY be returned in a <tt>result.credentials</tt> array; omission of metadata does not negate completion.</t>
        <sourcecode type="json"><![CDATA[{
  "operation": "acquire",
  "protocol": "openid4vci",
  "request": {
    "credential_offer_uri": "https://issuer.example/offers/9F4E"
  }
}]]></sourcecode>
      </section>
      <section anchor="openid4vp">
        <name>OpenID4VP Presentation</name>
        <t>The identifier <tt>openid4vp</tt> selects <tt>present</tt> using OpenID for Verifiable Presentations 1.0 <xref target="OPENID4VP"/>. The request object carries the outer Authorization Request parameters as string-valued members. Parameters received in a query string are URL-decoded once; JSON-valued parameters remain serialized JSON strings. A Request Object in <tt>request</tt> remains its encoded string value, and a reference remains <tt>request_uri</tt>. The Agent MUST preserve all received parameters, including <tt>client_id</tt> and any <tt>request_uri_method</tt>.</t>
        <t>This mapping supports the <tt>direct_post</tt> and <tt>direct_post.jwt</tt> response modes. The Wallet MUST validate the request, including applicable outer-parameter and Request Object consistency rules, under OpenID4VP. Unsupported response modes or other required features produce <tt>unsupported-protocol</tt>. Digital Credentials API requests require a separate mapping that preserves their platform context.</t>
        <t>Completion requires successful processing of a presentation response by the Verifier's response endpoint as defined by OpenID4VP and initiation of any required user-agent redirection. Sending an Authorization Error Response does not complete a presentation operation. Required interaction is arranged by the Wallet; a Verifier continuation URI is not automatically an A2WP interaction URI. The base mapping returns no presentation result members. Application authorization and completion of the Verifier's subsequent workflow remain outside this guarantee.</t>
        <sourcecode type="json"><![CDATA[{
  "operation": "present",
  "protocol": "openid4vp",
  "request": {
    "client_id": "x509_san_dns:verifier.example",
    "request_uri": "https://verifier.example/requests/4187",
    "request_uri_method": "get"
  },
  "context": {
    "purpose": "Present organization membership for onboarding"
  }
}]]></sourcecode>
      </section>
    </section>
    <section anchor="http">
      <name>HTTPS Binding</name>
      <t>The HTTP binding uses HTTPS <xref target="RFC9110"/> and JSON with the <tt>application/json</tt> media type. Endpoint URLs are supplied through metadata or trusted configuration; the example paths are not fixed protocol paths. Request bodies MUST be UTF-8 JSON objects. Unsupported media types receive HTTP 415; malformed A2WP messages receive HTTP 400.</t>
      <t>Responses containing credential metadata, operation representations, or operation errors MUST include <tt>Cache-Control: no-store</tt>. Status and interaction URIs MUST use HTTPS. The Agent MUST NOT forward Wallet authorization credentials to a different resource or follow a redirect with those credentials without an independently established authorization relationship.</t>
      <section anchor="http-methods">
        <name>Methods and Responses</name>
        <table>
          <thead>
            <tr>
              <th>Request</th>
              <th>Response</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>POST operation endpoint</td>
              <td>202 and an operation representation if nonterminal; 201 and a representation if already terminal. Location identifies the status URI.</td>
            </tr>
            <tr>
              <td>GET status URI</td>
              <td>200 and the current representation, including when the operation itself has failed.</td>
            </tr>
            <tr>
              <td>DELETE status URI</td>
              <td>200 and the cancelled representation, or 409 with not-cancellable. Cancellation does not remove the status resource.</td>
            </tr>
            <tr>
              <td>POST query endpoint</td>
              <td>200 and a query response.</td>
            </tr>
          </tbody>
        </table>
        <t>The Wallet SHOULD include <tt>Retry-After</tt> when returning a nonterminal operation. An Agent MUST respect that polling guidance when present and SHOULD otherwise use bounded backoff. A Wallet MAY return HTTP 429 with <tt>Retry-After</tt> when limiting requests. The Wallet MUST authorize every protected request, including requests made with renewed credentials.</t>
        <t>A missing, expired, or inaccessible operation MAY receive HTTP 404 to avoid revealing its existence. This differs from an operation whose execution expired and whose retained representation reports <tt>failed</tt>.</t>
      </section>
      <section anchor="access-protection">
        <name>Access Protection and OAuth Profile</name>
        <t>Deployments MUST authenticate and authorize access to protected endpoints. Establishing identities, acquiring authentication credentials, and expressing delegated authority are outside the core protocol. Support for OAuth 2.0 is RECOMMENDED. Other mechanisms can be agreed by deployment or profile.</t>
        <t>In the OAuth profile, the Wallet is an OAuth 2.0 Protected Resource <xref target="RFC6749"/> and validates tokens for the Wallet resource and requested access. Implementations MUST follow applicable OAuth security requirements <xref target="RFC9700"/>. Bearer use follows <xref target="RFC6750"/>. Sender-constrained tokens are RECOMMENDED; when DPoP is used, the Agent and Wallet MUST follow <xref target="RFC9449"/>, including proof and token-binding validation.</t>
        <t>This profile defines <tt>a2wp.acquire</tt> and <tt>a2wp.present</tt> for their corresponding operations, and <tt>a2wp.query</tt> for credential query. The Wallet MUST require the corresponding scope for operation creation or query. Reading or cancelling an operation requires the scope corresponding to its type and authorization for that particular operation. These scopes do not replace Wallet disclosure policy or grant access to other Agents' operations.</t>
      </section>
      <section anchor="metadata">
        <name>Wallet Metadata</name>
        <t>Wallet selection and initial configuration are deployment-specific. The OAuth profile SHOULD publish A2WP capabilities using Protected Resource Metadata <xref target="RFC9728"/>. When that mechanism is used, its discovery and resource-identifier validation requirements apply. Other deployments can supply these same A2WP fields through trusted configuration.</t>
        <dl newline="true" spacing="compact">
          <dt>
            <tt>a2wp_operation_endpoint</tt>
          </dt>
          <dd>
            <t>REQUIRED string: the absolute HTTPS URL for creating operations.</t>
          </dd>
          <dt>
            <tt>a2wp_operations_supported</tt>
          </dt>
          <dd>
            <t>REQUIRED nonempty array of distinct strings drawn from <tt>acquire</tt> and <tt>present</tt>, or identifiers defined by an agreed extension.</t>
          </dd>
          <dt>
            <tt>a2wp_protocols_supported</tt>
          </dt>
          <dd>
            <t>REQUIRED nonempty array of distinct protocol-mapping identifier strings. Each advertised mapping MUST be usable with at least one advertised operation; each advertised operation MUST have at least one applicable advertised mapping.</t>
          </dd>
          <dt>
            <tt>a2wp_credential_query_endpoint</tt>
          </dt>
          <dd>
            <t>OPTIONAL string: the absolute HTTPS URL for credential query. Its presence advertises query support; its absence means query is not advertised.</t>
          </dd>
        </dl>
        <sourcecode type="json"><![CDATA[{
  "resource": "https://wallet.example",
  "authorization_servers": [
    "https://auth.example"
  ],
  "a2wp_operation_endpoint": "https://wallet.example/operations",
  "a2wp_operations_supported": [
    "acquire",
    "present"
  ],
  "a2wp_protocols_supported": [
    "openid4vci",
    "openid4vp"
  ],
  "a2wp_credential_query_endpoint":
    "https://wallet.example/credentials/query"
}]]></sourcecode>
      </section>
    </section>
    <section anchor="errors">
      <name>Errors</name>
      <t>An operation error object contains a REQUIRED <tt>code</tt> string and an OPTIONAL <tt>detail</tt> string intended for human explanation. Agents MUST NOT use detail text as a machine-readable instruction. The following codes are defined by this document.</t>
      <dl newline="true" spacing="compact">
        <dt>
          <tt>invalid-request</tt>
        </dt>
        <dd>
          <t>Malformed request, unsupported filter, or inconsistent parameters.</t>
        </dd>
        <dt>
          <tt>unsupported-operation</tt>
        </dt>
        <dd>
          <t>The requested operation is not supported.</t>
        </dd>
        <dt>
          <tt>unsupported-protocol</tt>
        </dt>
        <dd>
          <t>The mapping or a required external protocol feature is not supported for the operation.</t>
        </dd>
        <dt>
          <tt>not-authorized</tt>
        </dt>
        <dd>
          <t>The authenticated caller lacks access to the requested A2WP resource or operation.</t>
        </dd>
        <dt>
          <tt>policy-denied</tt>
        </dt>
        <dd>
          <t>The operation or required disclosure was denied by Wallet policy or an approving actor.</t>
        </dd>
        <dt>
          <tt>interaction-expired</tt>
        </dt>
        <dd>
          <t>A required interaction expired before completion.</t>
        </dd>
        <dt>
          <tt>operation-expired</tt>
        </dt>
        <dd>
          <t>The operation expired before completion.</t>
        </dd>
        <dt>
          <tt>external-protocol-error</tt>
        </dt>
        <dd>
          <t>The external exchange failed.</t>
        </dd>
        <dt>
          <tt>outcome-unknown</tt>
        </dt>
        <dd>
          <t>The Wallet stopped processing but cannot establish the external outcome.</t>
        </dd>
        <dt>
          <tt>not-cancellable</tt>
        </dt>
        <dd>
          <t>The Wallet cannot provide the cancellation guarantees for this operation.</t>
        </dd>
      </dl>
      <t>The HTTP binding MUST use Problem Details <xref target="RFC9457"/> with media type <tt>application/problem+json</tt> for A2WP request errors, with the error code in a <tt>code</tt> extension member. This document uses <tt>about:blank</tt> as the problem type and defines no error URN namespace. Authentication challenges and errors prescribed by the selected authentication mechanism retain their required status codes and headers.</t>
      <t>Request errors use HTTP 400 for <tt>invalid-request</tt>, <tt>unsupported-operation</tt>, and <tt>unsupported-protocol</tt>; HTTP 403 for <tt>not-authorized</tt> and <tt>policy-denied</tt>; and HTTP 409 for <tt>not-cancellable</tt>. Once an operation has been accepted, execution failures are reported in its <tt>error</tt> member, not as a failed HTTP status retrieval. A Wallet MAY use <tt>not-authorized</tt> instead of <tt>policy-denied</tt> when further explanation would disclose protected information.</t>
      <sourcecode type="json"><![CDATA[{
  "type": "about:blank",
  "title": "Forbidden",
  "status": 403,
  "code": "not-authorized"
}]]></sourcecode>
    </section>
    <section anchor="security">
      <name>Security Considerations</name>
      <section anchor="authorization-boundary">
        <name>Authorization Boundary</name>
        <t>A compromised or manipulated Agent can request unintended credential use. Independent Wallet authorization limits that authority but cannot detect every misuse allowed by an overly broad policy. The Wallet MUST authorize the actual external request, counterparty, and disclosure before execution. Merely receiving a request, verifying a signature, or finding a matching credential is not authorization.</t>
        <t>When approval is required, the Wallet MUST ensure that the executed action remains within the approved scope. Material changes to the external request or disclosure require renewed evaluation. The evidence and mechanisms used for authorization and approval are implementation concerns. Agent-provided purpose text MUST be distinguished from verified information when presented to an approver.</t>
        <t>A presentation establishes only what its credential and external protocol support. Any association with an Agent's remote application session needs the protections of that application integration. An advisory A2WP task identifier does not establish this association.</t>
      </section>
      <section anchor="references-and-network">
        <name>References and Network Access</name>
        <t>Knowledge of a handle, operation identifier, cursor, or interaction URI MUST NOT by itself authorize credential use or access to status. Operation identifiers SHOULD be unpredictable to reduce enumeration. Wallets MUST bind protected objects to the applicable authorization context; renewed credentials do not automatically confer access to unrelated operations.</t>
        <t>Wallets MUST validate untrusted external URIs and enforce deployment-appropriate network access policy when resolving requests, metadata, and redirects. Implementations need to account for SSRF, DNS rebinding, unsafe schemes, and resource exhaustion. External-protocol tokens and A2WP access credentials MUST NOT be forwarded to unintended recipients.</t>
        <t>Wallets SHOULD bound input sizes, external fetches, concurrent operations, and repeated interaction requests. Appropriate limits are deployment-specific. Cancellation, expiry, and timeouts cannot retract information already disclosed.</t>
      </section>
      <section anchor="data-minimization">
        <name>Data Minimization</name>
        <t>Credential existence, metadata, operation status, and error differences can reveal sensitive information. Wallets MUST apply disclosure policy to all such outputs and SHOULD return only information needed by the Agent. Metadata properties MAY describe authorized type, issuer, or expiry information; they MUST NOT serve as a channel for exporting credentials or presentations.</t>
        <t>Context, interaction links, and credential offers can contain personal information or secrets. Wallets and Agents SHOULD minimize their retention and avoid including sensitive values in logs and error details. Wallets SHOULD record enough information to audit authorization and disclosure while protecting the audit records. This specification does not prescribe an audit schema or retention period.</t>
      </section>
    </section>
    <section anchor="extensions">
      <name>Extensibility</name>
      <t>Additional operations, mappings, filters, and metadata properties can be defined by other specifications or deployment profiles. A mapping identifier defined by this document has the semantics stated here; an incompatible mapping requires a different identifier. New operation and mapping identifiers SHOULD be absolute URIs controlled by their defining party to avoid collisions.</t>
      <t>Recipients MUST ignore unrecognized optional members of A2WP envelopes and representations. Unknown operation or mapping identifiers MUST be rejected. Unknown filters MUST be rejected as specified in <xref target="query"/>. Processing of members inside a protocol-specific request follows its mapping, and properties inside advisory context have no standardized meaning.</t>
      <t>An extension whose processing is necessary for authorization or correct execution MUST be explicitly agreed before use, for example through a distinct advertised mapping identifier. Such a requirement MUST NOT be conveyed only by a field an older recipient would ignore. Unknown response status values or error codes MUST NOT be treated as success. Extensions MUST preserve Wallet authority and the disclosure restrictions in <xref target="model"/>.</t>
    </section>
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document requests the following registrations in the OAuth Protected Resource Metadata registry established by <xref target="RFC9728"/>.</t>
      <t>No registration is requested for the application-specific OAuth scope values or JSON error codes defined here.</t>
      <section anchor="iana-a2wp-operation-endpoint">
        <name>a2wp_operation_endpoint</name>
        <dl newline="true" spacing="compact">
          <dt>Metadata Name</dt>
          <dd>
            <t>
              <tt>a2wp_operation_endpoint</tt>
            </t>
          </dd>
          <dt>Metadata Description</dt>
          <dd>
            <t>URL of the Wallet endpoint for creating A2WP operations.</t>
          </dd>
          <dt>Change Controller</dt>
          <dd>
            <t>IETF</t>
          </dd>
          <dt>Specification Document(s)</dt>
          <dd>
            <t>
              <xref target="metadata"/> of this document.</t>
          </dd>
        </dl>
      </section>
      <section anchor="iana-a2wp-operations-supported">
        <name>a2wp_operations_supported</name>
        <dl newline="true" spacing="compact">
          <dt>Metadata Name</dt>
          <dd>
            <t>
              <tt>a2wp_operations_supported</tt>
            </t>
          </dd>
          <dt>Metadata Description</dt>
          <dd>
            <t>JSON array of A2WP operation identifiers supported by the Wallet.</t>
          </dd>
          <dt>Change Controller</dt>
          <dd>
            <t>IETF</t>
          </dd>
          <dt>Specification Document(s)</dt>
          <dd>
            <t>
              <xref target="metadata"/> of this document.</t>
          </dd>
        </dl>
      </section>
      <section anchor="iana-a2wp-protocols-supported">
        <name>a2wp_protocols_supported</name>
        <dl newline="true" spacing="compact">
          <dt>Metadata Name</dt>
          <dd>
            <t>
              <tt>a2wp_protocols_supported</tt>
            </t>
          </dd>
          <dt>Metadata Description</dt>
          <dd>
            <t>JSON array of external-protocol mapping identifiers supported by the Wallet.</t>
          </dd>
          <dt>Change Controller</dt>
          <dd>
            <t>IETF</t>
          </dd>
          <dt>Specification Document(s)</dt>
          <dd>
            <t>
              <xref target="metadata"/> of this document.</t>
          </dd>
        </dl>
      </section>
      <section anchor="iana-a2wp-credential-query-endpoint">
        <name>a2wp_credential_query_endpoint</name>
        <dl newline="true" spacing="compact">
          <dt>Metadata Name</dt>
          <dd>
            <t>
              <tt>a2wp_credential_query_endpoint</tt>
            </t>
          </dd>
          <dt>Metadata Description</dt>
          <dd>
            <t>URL of the optional Wallet endpoint for querying credential metadata.</t>
          </dd>
          <dt>Change Controller</dt>
          <dd>
            <t>IETF</t>
          </dd>
          <dt>Specification Document(s)</dt>
          <dd>
            <t>
              <xref target="metadata"/> of this document.</t>
          </dd>
        </dl>
      </section>
    </section>
  </middle>
  <back>
    <references>
      <name>Normative References</name>
      <reference anchor="OPENID4VCI" target="https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html">
        <front>
          <title>OpenID for Verifiable Credential Issuance 1.0</title>
          <author fullname="Torsten Lodderstedt" initials="T." surname="Lodderstedt"/>
          <author fullname="Kristina Yasuda" initials="K." surname="Yasuda"/>
          <author fullname="Tobias Looker" initials="T." surname="Looker"/>
          <author fullname="Paul Bastian" initials="P." surname="Bastian"/>
          <date year="2025" month="September" day="16"/>
        </front>
      </reference>
      <reference anchor="OPENID4VP" target="https://openid.net/specs/openid-4-verifiable-presentations-1_0.html">
        <front>
          <title>OpenID for Verifiable Presentations 1.0</title>
          <author fullname="Oliver Terbu" initials="O." surname="Terbu"/>
          <author fullname="Torsten Lodderstedt" initials="T." surname="Lodderstedt"/>
          <author fullname="Kristina Yasuda" initials="K." surname="Yasuda"/>
          <author fullname="Daniel Fett" initials="D." surname="Fett"/>
          <author fullname="Joseph Heenan" initials="J." surname="Heenan"/>
          <date year="2025" month="July" day="9"/>
        </front>
      </reference>
      <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC3339" target="https://www.rfc-editor.org/info/rfc3339">
        <front>
          <title>Date and Time on the Internet: Timestamps</title>
          <author fullname="G. Klyne" initials="G." surname="Klyne"/>
          <author fullname="C. Newman" initials="C." surname="Newman"/>
          <date month="July" year="2002"/>
        </front>
        <seriesInfo name="RFC" value="3339"/>
        <seriesInfo name="DOI" value="10.17487/RFC3339"/>
      </reference>
      <reference anchor="RFC6749" target="https://www.rfc-editor.org/info/rfc6749">
        <front>
          <title>The OAuth 2.0 Authorization Framework</title>
          <author fullname="D. Hardt" initials="D." role="editor" surname="Hardt"/>
          <date month="October" year="2012"/>
        </front>
        <seriesInfo name="RFC" value="6749"/>
        <seriesInfo name="DOI" value="10.17487/RFC6749"/>
      </reference>
      <reference anchor="RFC6750" target="https://www.rfc-editor.org/info/rfc6750">
        <front>
          <title>The OAuth 2.0 Authorization Framework: Bearer Token Usage</title>
          <author fullname="M. Jones" initials="M." surname="Jones"/>
          <author fullname="D. Hardt" initials="D." surname="Hardt"/>
          <date month="October" year="2012"/>
        </front>
        <seriesInfo name="RFC" value="6750"/>
        <seriesInfo name="DOI" value="10.17487/RFC6750"/>
      </reference>
      <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
      <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
        <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"/>
        </front>
        <seriesInfo name="STD" value="90"/>
        <seriesInfo name="RFC" value="8259"/>
        <seriesInfo name="DOI" value="10.17487/RFC8259"/>
      </reference>
      <reference anchor="RFC9110" target="https://www.rfc-editor.org/info/rfc9110">
        <front>
          <title>HTTP Semantics</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"/>
        </front>
        <seriesInfo name="STD" value="97"/>
        <seriesInfo name="RFC" value="9110"/>
        <seriesInfo name="DOI" value="10.17487/RFC9110"/>
      </reference>
      <reference anchor="RFC9449" target="https://www.rfc-editor.org/info/rfc9449">
        <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"/>
        </front>
        <seriesInfo name="RFC" value="9449"/>
        <seriesInfo name="DOI" value="10.17487/RFC9449"/>
      </reference>
      <reference anchor="RFC9457" target="https://www.rfc-editor.org/info/rfc9457">
        <front>
          <title>Problem Details for HTTP APIs</title>
          <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
          <author fullname="E. Wilde" initials="E." surname="Wilde"/>
          <author fullname="S. Dalal" initials="S." surname="Dalal"/>
          <date month="July" year="2023"/>
        </front>
        <seriesInfo name="RFC" value="9457"/>
        <seriesInfo name="DOI" value="10.17487/RFC9457"/>
      </reference>
      <reference anchor="RFC9700" target="https://www.rfc-editor.org/info/rfc9700">
        <front>
          <title>Best Current Practice for OAuth 2.0 Security</title>
          <author fullname="Torsten Lodderstedt" initials="T." surname="Lodderstedt"/>
          <author fullname="John Bradley" initials="J." surname="Bradley"/>
          <author fullname="Andrey Labunets" initials="A." surname="Labunets"/>
          <author fullname="Daniel Fett" initials="D." surname="Fett"/>
          <date year="2025" month="January"/>
        </front>
        <seriesInfo name="BCP" value="240"/>
        <seriesInfo name="RFC" value="9700"/>
        <seriesInfo name="DOI" value="10.17487/RFC9700"/>
      </reference>
      <reference anchor="RFC9728" target="https://www.rfc-editor.org/info/rfc9728">
        <front>
          <title>OAuth 2.0 Protected Resource Metadata</title>
          <author fullname="M.B. Jones" initials="M.B." surname="Jones"/>
          <author fullname="P. Hunt" initials="P." surname="Hunt"/>
          <author fullname="A. Parecki" initials="A." surname="Parecki"/>
          <date month="April" year="2025"/>
        </front>
        <seriesInfo name="RFC" value="9728"/>
        <seriesInfo name="DOI" value="10.17487/RFC9728"/>
      </reference>
    </references>
    <section anchor="example">
      <name>Example Operation Exchange</name>
      <t>These examples show the OAuth profile with DPoP. Tokens and proofs are abbreviated; message framing is omitted. The metadata has identified <tt>https://wallet.example/operations</tt> as the operation endpoint. The external request is represented as in <xref target="openid4vp"/>.</t>
      <sourcecode type="http"><![CDATA[POST /operations HTTP/1.1
Host: wallet.example
Authorization: DPoP eyJ...
DPoP: eyJ...
Content-Type: application/json]]></sourcecode>
      <sourcecode type="json"><![CDATA[{
  "operation": "present",
  "protocol": "openid4vp",
  "request": {
    "client_id": "x509_san_dns:verifier.example",
    "request_uri": "https://verifier.example/requests/4187"
  }
}]]></sourcecode>
      <t>The Wallet accepts the request and returns HTTP 202, a Location header equal to the status URI, Cache-Control: no-store, and the following representation. It can arrange interaction through its own approval channel without returning an interaction URI.</t>
      <sourcecode type="json"><![CDATA[{
  "operation_id": "op_x2p9E4Hc7mR6vQ8sN1tB5A",
  "operation": "present",
  "protocol": "openid4vp",
  "status": "interaction_required",
  "status_uri":
    "https://wallet.example/operations/op_x2p9E4Hc7mR6vQ8sN1tB5A"
}]]></sourcecode>
      <t>The Agent subsequently polls the status URI using its authorized access. After the mapping's completion conditions have been met, an HTTP 200 response contains:</t>
      <sourcecode type="json"><![CDATA[{
  "operation_id": "op_x2p9E4Hc7mR6vQ8sN1tB5A",
  "operation": "present",
  "protocol": "openid4vp",
  "status": "completed",
  "status_uri":
    "https://wallet.example/operations/op_x2p9E4Hc7mR6vQ8sN1tB5A",
  "completed_at": "2026-09-19T10:22:41Z"
}]]></sourcecode>
      <t>If the Wallet instead loses confirmation of the external outcome and stops processing, status retrieval still succeeds with HTTP 200, but returns:</t>
      <sourcecode type="json"><![CDATA[{
  "operation_id": "op_x2p9E4Hc7mR6vQ8sN1tB5A",
  "operation": "present",
  "protocol": "openid4vp",
  "status": "failed",
  "status_uri":
    "https://wallet.example/operations/op_x2p9E4Hc7mR6vQ8sN1tB5A",
  "error": {
    "code": "outcome-unknown"
  }
}]]></sourcecode>
    </section>
  </back>
</rfc>
