The verifiable identity protocol
for the internet.
HTTP shipped with authentication. It never shipped with proof. x401 is the protocol that completes the challenge layer of the web.
Identity negotiation for the agentic web.
HTTP shipped in the nineties with a way to challenge a caller for credentials: 401 Unauthorized, WWW-Authenticate. For thirty years, that was enough. Every system that needed to know who the caller really was wrote its own answer in the app layer.
That model assumed a person at a browser. The agent era breaks the assumption. Calls now come from workloads, autonomous agents, and delegated service identities. The route on the other end needs to know what the caller can prove, not just what token it carries. x401 makes that proof a first-class part of the protocol.
Read the full specWhat can x401 do?
Now agents can respond to an identity challenge on behalf of the person they serve.
Banking
Open an account with an identity that satisfies KYC and AML.
Step-up auth
Change wire instructions, require additional proof not just a login.
Prescriptions
Refill a script tied to a verified patient identity, not typed in SSNs.
Organization Credentials
Verify an active board association before joining a meeting.
Age gate
Place a bet by answering “over 18”. No DOB ever leaves the wallet.
Ticketing
Sell concert tickets to people, not bots, with proof of personhood.
Travel
Request identity and a passport when booking travel.
See all demos
Try each scenario against a real 401 challenge.
A curated registry, not a research project.
x401 can ask for any claim. The registry curates the issuers the industry agrees to accept, so when a route demands proof there's already a trusted source for it. The same protocol works for age, identity, license, employment, or ownership. One handshake. Proof for anything.
When an agent makes a request that requires ID.
Four steps between the request and the response.
Proof requirement
The route says no, and says why. The response carries the proof requirement in the Proof-Required header: which credentials, which challenge, which trust list.
Wallet presentation
The agent forwards the requirement to its wallet as an OpenID4VP request, DCQL query intact. The wallet returns a verifiable presentation signed for the agent.
Retry with proof
The agent retries the route with the presentation in the Authorization header. The verifier checks four things: challenge match, agent match, credential satisfaction, issuer trust.
Token exchange
The agent trades the presentation for a short-lived Bearer token. Every request after this one skips the proof step entirely.
On the wire.
A verifier returns 401 with a base64url-encoded x401 payload. The agent decodes it, fetches a presentation from its wallet, and retries. The entire handshake runs over plain HTTP request and response headers.
HTTP/1.1 401 Unauthorized
Proof-Required: eyJ2ZXJzaW9uIjoiMC4xLjAi...
Cache-Control: no-store{
"scheme": "x401",
"version": "0.1.0",
"proof": {
"presentation_protocol": "openid4vp",
"dcql_query": {
"credentials": [{
"id": "identity",
"format": "dc+sd-jwt",
"meta": { "vct_values": ["https://credentials.example.com/identity"] },
"claims": [
{ "path": ["given_name"] },
{ "path": ["family_name"] },
{ "path": ["address"] },
{ "path": ["birth_date"] },
{ "path": ["kyc_status"], "values": ["verified"] }
]
}]
},
"challenge": {
"value": "x401:aHR0cHM6Ly9yZXN0L2Nx...",
"expires_at": "2026-05-08T18:45:00Z"
},
"oauth": {
"token_endpoint": "https://research.example.com/oauth/token"
},
"issuers": {
"trust_establishment_url":
"https://research.example.com/.well-known/x401/trust/identity-..."
}
}
}import { fetchWithX401 } from "@x401/client";
const res = await fetchWithX401("https://api.fintech.example/v1/accounts", {
method: "POST",
body: JSON.stringify({ plan: "business" }),
agentId: "did:web:agent.example",
wallet, // any OpenID4VP-capable wallet
trustList: "auto", // resolve issuers from proof.issuers
});
// Auto-handles: decode payload → build OpenID4VP request →
// wallet presentation → retry with VP Artifact.
console.log(await res.json());POST /v1/accounts HTTP/1.1
Host: api.fintech.example
Proof-Presentation: eyJhZ2VudF9pZCI6ImRpZDp3ZWI6YWdlbnQuZXhhbXBsZS..."It composes. It doesn't compete.
x401 is a response format. It carries existing credential standards into a single HTTP challenge, so a route can declare its proof requirement. No new stack to invent.
x401 + x402.
Two protocols. One boundary. x402 lets agents pay. x401 lets agents prove who's paying. Stack the two and a single HTTP exchange handles every regulated payment flow on the web. KYC'd onboarding. Travel Rule transfers. Age-gated commerce. Sanctions screening. Anywhere money has to know your name.
Who are you?
The route asks the agent to reveal identity, organizational membership, or another credential. The agent presents a verifiable credential, the verifier validates it, the route opens.
HTTP/1.1 401 Unauthorized Proof-Required: <base64url-x401-payload>
Can you pay?
The route asks the agent to settle a payment. The agent presents a payment artifact, the verifier confirms it, the route opens.
HTTP/1.1 402 Payment Required Payment-Required: payment-object
Run them in sequence: prove first, then pay. Run them in parallel: both required, in any order. Or use either on its own. Neither artifact is accepted as the other.
Meet the creators
x401 is built in the open by Proof and a group of contributors from across the identity ecosystem. Want to talk through your use case, collaborate on the spec, or just say hello? The team would love to hear from you.