Internet-Draftdraft-senarath-a2wp-01

Agents use credentials. Wallets hold them.

The Agent-to-Wallet Protocol (A2WP) lets an AI agent ask its wallet to collect or present credentials, its own or ones it was given, while the wallet keeps the keys, the policy and the final say. It is independent of the transport, so it works over MCP, HTTPS or anything else.

The problem

Agents need credentials. There is no safe way to hand them one.

API keys say nothing

Agents prove who they are with a separate API key for every service. A key does not say who made the agent, who runs it or whether anyone checked it, and anyone who copies one becomes the agent.

Agents mishandle credentials

Given a credential offer link and no wallet, an agent we tested tried to open it like a web page. Put a credential or key in its context and the model can read it, log it, or be tricked into sending it somewhere else.

Wallets have no agent interface

OpenID4VCI and OpenID4VP connect wallets to issuers and verifiers, but they assume a person at the device. Nothing standard lets an agent ask a wallet to act for it, so every pairing is custom.

A2WP splits the job in two. The agent says what it needs. The wallet decides and does it.

How A2WP works

Two operations, one rule.

The agent hands its wallet an offer or a request, exactly as it got it. The wallet works out which, does the work, and the agent only learns the outcome.

Agentstates intent only

Wallet

policykeys
no credential yet
MembershipSD-JWT VC
Issuerissuer.example
Verifierverifier.example

Step 7 of 7

The agent checks the status: completed. It never sees the credential.

status: completed

Under the hood

Step by step.

An operation looks the same over every binding. Each call is authenticated as one agent, and that agent's credentials and policy apply. Long values are shortened.

Acquire a credential

  1. 1

    The agent hands its wallet the offer

    An issuer gave the agent a credential offer link. The agent submits it to its wallet exactly as it got it and never opens it itself. The wallet works out that it is an offer and replies at once with an operation to follow. Submitting the same link again returns the same operation, so a retry cannot redeem it twice.

    Submit
    {
      "request": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example%2Foffers%2F9c1e"
    }
    Operation
    {
      "id": "op_Qm7cZt0sLe…",
      "status": "pending"
    }
  2. 2

    The wallet runs OpenID4VCI

    The wallet talks to the issuer itself. The agent never sees a token, a key or the credential.

    • Loads the offer and the issuer's metadata
    • Checks the issuer and credential type against policy, before redeeming anything
    • Asks the user for a transaction code on the wallet's own page, never through the agent
    • Redeems the pre-authorized code
    • Creates a fresh holder key and proves it controls it
    • Verifies the SD-JWT VC: issuer signature, chain, type and holder binding
    • Stores the credential with the agent that asked for it
  3. 3

    The agent learns the outcome

    When the operation completes, that is all the agent learns. The credential stays in the wallet, ready for the next request. An issuance has no continuation, so the agent carries on with its task.

    Operation
    {
      "id": "op_Qm7cZt0sLe…",
      "status": "completed"
    }

Present a credential

  1. 1

    The agent hands its wallet the request

    A site showed the agent a presentation request, for example as an Open in wallet link at sign-in. The agent submits the link to its wallet unchanged, the same call it uses for offers, and gets an operation back.

    Submit
    {
      "request": "openid4vp://authorize?client_id=x509_san_dns%3Atickets.example&request_uri=https%3A%2F%2Ftickets.example%2Frequest%2F7f3a"
    }
    Operation
    {
      "id": "op_4Tk9xQ2mVb…",
      "status": "pending"
    }
  2. 2

    The wallet runs OpenID4VP

    Everything that touches the credential happens inside the wallet, out of the agent's reach.

    • Fetches the verifier's signed request and checks its certificate chain
    • Checks that the certificate names the verifier's client_id
    • Runs the DCQL query against this agent's credentials only
    • Applies policy: may this agent share these claims with this verifier?
    • Builds a minimal disclosure plus a key-binding JWT for this verifier
    • Posts the response straight to the verifier, not through the agent
  3. 3

    Sometimes, a person decides

    Whether to ask the user is the wallet's policy: for example a first visit to a site, more claims than last time, or an unfamiliar issuer. The operation stays pending and carries an interaction. The agent passes the link to its user and keeps checking the operation until it finishes. It never opens the link, and the wallet's page signs the user in rather than trusting whoever holds the link.

    Operation
    {
      "id": "op_4Tk9xQ2mVb…",
      "status": "pending",
      "interaction": {
        "uri": "https://wallet.example/approve/ia_Acw…",
        "expires_at": "2026-10-13T09:40:00Z"
      }
    }
  4. 4

    The agent picks up where it left off

    The verifier answers the wallet with a continuation, and the wallet passes it to the agent unchanged. The agent opens it in the browser session where it found the request, and the site carries on with the checkout. What was disclosed went only to the verifier.

    Operation
    {
      "id": "op_4Tk9xQ2mVb…",
      "status": "completed",
      "continuation": "https://tickets.example/checkout/chk_MJnD?response_code=0915…"
    }

Bindings

The draft defines the calls, not the transport.

A binding carries the three calls and decides how the wallet authenticates each agent, for example with a bearer key or DPoP. These two are sketches; neither is part of -01.

MCP

The wallet is an MCP server and each call is a tool, so any MCP-capable agent can use it with no extra code. The PoC ran an earlier version of this with a real agent.

submit(request)
get(id, wait_seconds)
cancel(id)

HTTPS

The same three calls as HTTP resources, for agents and services that do not speak MCP.

POST   /operations
GET    /operations/{id}
DELETE /operations/{id}

Where A2WP fits

Agents with their own ID

An agent carries a credential that says who it is and who runs it, from a registry that vouches for it, and signs in to any site that trusts the registry.

Read the story

Personal assistants

Your agent proves things about you, such as your age, with a credential you delegate from your own wallet for that one presentation. It never sees the credential behind the proof.

Enterprise agents

Each agent gets its own access to the wallet and its own credentials. People approve where policy says so, and one policy covers them all.