
Why Two AI Agents Need Cryptographic Identity Before They Say Hello
Picture two AI agents about to open a dialogue across organizational boundaries. A procurement agent at Company A reaches out to a supplier agent at Company B to negotiate an order. Neither has ever spoken to the other before. There is no shared backend, no pre-shared secret, no human in the loop to vouch for either side. The very first message arrives, and Company B's agent has to decide what to do with it.
What can it actually verify in that instant?
With today's web stack, surprisingly little about the agent itself. TLS will confirm that the certificate of the calling domain is valid, which tells the supplier agent that some service at company-a.example owns a private key matching a DNS name. It does not say which agent inside that infrastructure made the call, who owns it, or what it is allowed to do. OAuth and OpenID Connect were designed around a human user who logs in, consents, and hands a token to a client. Strip out the human and most of the protocol's trust assumptions go with them. An API key is even thinner. It proves that whoever is calling possesses a particular string. That is closer to a password than to an identity.
The result is a gap between what the network layer guarantees and what the agent layer needs to know. Three things have to be answered together at the start of a cross-domain dialogue, and they have to be answered automatically without a human approving anything:
- Who is this agent, as a stable entity that persists across sessions and deployments
- Who controls it, meaning which person or organization is accountable for what it does
- What is it authorized to do in this specific dialogue, including any delegated authority it carries from its principal
Current protocols answer one of these at most, and only partially. Recent agent-to-agent standards such as A2A and the payment extensions built on top of it solved interoperability and economic coordination, which was the right first move. But they sit on top of the same web security primitives, so they inherited the same human-centric assumptions about session establishment and credential management.
Why does this matter now and not five years ago? Because the topology has changed. As long as agents lived inside one company's walled garden, identity was implicit. The platform knew who was who, and access control was a configuration problem. Once agents start to act as economic actors that hold budgets, sign contracts, fetch regulated data, and negotiate with strangers, that implicit trust evaporates. The supplier agent in our scenario cannot rely on Company A having registered Company A's procurement agent in any directory it controls. There is no directory.
So the supplier agent is left with a binary choice. Refuse every unknown caller, which kills the entire premise of open agent-to-agent commerce. Or accept whatever arrives and rely on downstream checks, which is how exposed APIs get drained. Neither is a serious answer for systems that are about to move money and data autonomously.
The interesting question is what a real answer looks like. It has to give the agent receiving that first message a way to cryptographically verify the caller's identity, resolve who stands behind it, and inspect what authority it actually carries, without any prior bilateral setup between Company A and Company B. It has to work the first time two agents meet, and it has to keep working when the agents rotate keys, when their owners change, and when their authorizations expire.
What DIDs and Verifiable Credentials actually are
The answer the research builds on is a pair of W3C standards that were designed for exactly this kind of cross-domain verification: Decentralized Identifiers and Verifiable Credentials. They are often described together under the label self-sovereign identity, which is accurate but not very useful when you are trying to understand what the bytes on the wire look like. So let us look at them as the agent uses them.
A Decentralized Identifier is an identifier that the subject creates and controls itself, without asking any registrar for permission. It looks like a URI, for example did:web:agents.company-a.example:procurement-7 or did:key:z6Mk.... What makes it useful is not the string but what it resolves to. Resolving a DID returns a DID Document, a small JSON structure containing the public keys associated with the identifier, the verification methods that can be used against it, and the service endpoints where the subject can be reached. The DID Document is anchored on a ledger or on another verifiable data source, so anyone can fetch it and trust that it has not been tampered with.
Three properties of this design matter for agents. First, the DID Document contains no personal attributes. It carries keys and pointers, nothing else, so publishing it leaks nothing sensitive. Second, the subject can rotate its keys by publishing an updated DID Document, without involving a certificate authority and without changing the DID itself. The agent's identifier is stable across the entire life of the agent, even as its cryptographic material changes underneath. Third, the DID Document can declare deputies, meaning other DIDs that are authorized to act on behalf of this one. This is how human-to-agent ownership and agent-to-agent delegation get encoded directly into the identity layer rather than bolted on later.
A Verifiable Credential is a signed statement that one party makes about another. The structure is straightforward. It names an issuer, a subject, a set of claims, and a cryptographic proof. The issuer signs with the private key tied to its own DID. The subject is identified by its DID. The claims are arbitrary key-value assertions, and that is the part that makes VCs flexible enough to carry whatever the dialogue needs.
Concretely, the procurement agent in our scenario might hold three VCs in its store:
- One issued by Company A's HR system, asserting "this DID is owned by Company A, role procurement"
- One issued by Company A's finance system, asserting "this DID is authorized to commit funds up to 10,000 EUR per transaction, valid until end of quarter"
- One issued by an external compliance auditor, asserting "this DID operates under audit framework ISO 42001, certificate ID such-and-such"
Each of those issuers has its own DID, anchored on the same ledger or on a ledger the verifier can reach. So when the supplier agent receives one of these credentials, it can resolve the issuer's DID, fetch the issuer's public key, and verify the signature on the credential without contacting the issuer at all. The VC is self-contained and offline-verifiable. That is the property that makes it work at the first message between two agents who have never met.
Pairing the two primitives is what produces something useful. The DID gives the agent a stable cryptographic identity it controls. The VCs let third parties attach claims to that identity, claims that travel with the agent and can be presented to anyone. Neither piece on its own is enough. A DID without credentials proves only that the agent controls a key. Credentials without a DID have no stable subject to attach to. Together, they give the supplier agent everything it needs to answer the three questions from the previous section, in one handshake, without any prior relationship with Company A.
The trust handshake at the first message
Now the mechanics. Two agents have just opened a channel. Each holds its own DID and a small portfolio of Verifiable Credentials. What happens between "hello" and the moment they are willing to do business?
The handshake runs in four phases. None of them require Company A and Company B to have ever heard of each other before.
Phase 1, exchange of DIDs. Each agent sends its DID to the other. The supplier agent receives the procurement agent's DID, takes the method-specific part, and resolves it. If it is a did:web, resolution is an HTTPS fetch. If it is a ledger-anchored method like did:ion or did:ethr, resolution goes through the ledger. The result is the procurement agent's DID Document, with the current public key and the verification methods declared by the subject itself. The supplier agent does the same in reverse. At the end of this phase, both sides know which key they are supposed to be talking to. They do not yet know that the counterpart actually controls it.
Phase 2, proof of control. This is a challenge-response. The supplier agent sends a fresh nonce and asks the procurement agent to sign it with the private key bound to the DID it just presented. The procurement agent signs, returns the signature, and the supplier agent verifies it against the public key it pulled in phase one. Symmetric step in the other direction. This is the moment identity becomes authentication. Anyone can claim a DID. Only the legitimate controller can produce a valid signature against the key in the DID Document. Without this step, phase one is just an unverified label.
Phase 3, presentation of credentials. Each agent now decides which Verifiable Credentials are relevant to this specific dialogue and presents them. Selectivity matters. The procurement agent does not dump its entire credential store. It picks the subset that the dialogue requires, for instance the ownership VC issued by Company A and the spending-authority VC issued by Company A's finance system. If the supplier agent's policy requires a compliance attestation, the procurement agent adds the auditor-issued VC. The presentation is wrapped in a Verifiable Presentation, signed by the holder's DID, which proves that the agent presenting the credentials is the same subject they refer to.
Phase 4, verification of issuers. This is where the real trust decision happens. The supplier agent takes each VC, reads the issuer field, and resolves the issuer's DID on the ledger. It fetches the issuer's public key, checks the signature on the credential, and confirms the credential has not expired or been revoked. Revocation can be done in several ways depending on the deployment, including status lists published at a known endpoint or registry entries on the ledger. Then comes the policy check. The supplier agent asks itself, for each claim, whether the issuer is one it accepts as authoritative for that type of claim. A signature from Company A's HR system is acceptable for an ownership claim. A signature from a random self-issued DID is not acceptable for spending authority. This evaluation is local to the verifier and driven by its own configuration.
A few things are worth noticing about how this composes.
Trust is not transitive by default. The supplier agent does not trust Company A's HR system because Company A says so. It trusts that issuer because its own policy lists it as authoritative for ownership claims. If the policy does not list it, the credential is cryptographically valid but operationally ignored.
The handshake is stateless in the sense that nothing had to be set up in advance between the two organizations. Onboarding collapses into "configure the issuers you trust, for which claim types." New agents from new organizations join the system without any bilateral registration step.
The whole flow sits naturally on top of agent-to-agent transport protocols like A2A. The AgentCard that A2A uses to describe an agent can carry the DID. The first signed request after the handshake binds the application-layer session to the verified identity. The identity layer adds verification at the moment the channel opens, without replacing what A2A already does for routing and capability discovery.
Differentiated trust, and why it is the real shift
The handshake from the previous section produces a list of cryptographically valid claims about the counterpart. That list, on its own, is not a decision. It is raw material. The actual decision happens when the verifier maps those claims onto its own policy, and that mapping is where this model departs sharply from how authorization usually works on the web.
Call it differentiated trust. Each agent decides on its own, in real time, which credentials weigh how much, for which actions, from which issuers. There is no global authority that says "this token grants this scope." There is a verifier, a set of presented claims, and a local policy that composes them.
Walk through it with the procurement scenario. The supplier agent receives three Verifiable Credentials from the procurement agent.
- A VC signed by a national chamber of commerce, asserting that the controlling entity is the legal person Company A, registration number such-and-such
- A VC signed by Company A's internal finance system, asserting that this specific agent is authorized to commit funds up to 10,000 EUR per transaction
- A VC self-issued by the agent itself, asserting it prefers JSON over XML for response payloads
All three are cryptographically valid. None of them is automatically more trustworthy than the others. The supplier agent's policy is what assigns weight. A reasonable configuration looks like this. The chamber-of-commerce VC is accepted as sufficient evidence of organizational identity, because the supplier's policy lists that issuer as authoritative for legal-entity claims. The finance-system VC is accepted as sufficient evidence of spending authority, because the supplier's policy lists Company A's own finance DID as authoritative for delegations made by Company A about Company A's own agents. The self-issued VC is informational and carries no authorization weight, because the policy does not list the agent itself as an issuer for anything beyond preferences.
Notice what this is not. It is not an OAuth scope. There is no provider that pre-defines what the access token is good for. There is a composition of heterogeneous claims, each with a different issuer, evaluated against the verifier's own rules. The verifier is the one that says what counts.
This solves a problem that bilateral systems handle badly. Cross-domain authorization in the wild involves claims that come from different sources with different levels of authority over different things. The chamber of commerce is authoritative about legal existence, not about spending limits. The finance system is authoritative about its own delegations, not about regulatory compliance. The compliance auditor is authoritative about its audit, not about employment. A single authorization server cannot speak for all of them. Differentiated trust lets each issuer speak only for what it actually knows, and lets the verifier compose the answer.
The other consequence is operational. Two organizations that have never interacted can now do business at the agent layer without registering each other anywhere. The supplier agent does not need an account for Company A. It needs a configuration that says which issuers it accepts and for which claim types. New counterparts from new organizations show up, present credentials issued by parties the supplier already trusts, and the handshake completes. Onboarding moves from "register every counterparty" to "curate your set of trusted issuers." That is a meaningfully smaller and more stable problem.
There is a cost, and it should be named clearly. The trust policy is now itself a critical artifact. It decides what gets accepted and what does not, which means it decides what the agent will spend money on, what data it will release, and which counterparts it will engage with. A bug in the policy is a security incident. A stale entry in the trusted-issuer list is a quiet vulnerability. The policy needs versioning, review, and a process for adding and removing issuers. It is not a config file you set once and forget.
Where it breaks when the LLM is in charge of the procedure
The cryptographic primitives work. That is the first finding worth stating clearly, because it is easy to lose in the discussion of what does not work. The DID resolution, the challenge-response, the signature verification on Verifiable Credentials, the issuer lookup on the ledger, all of it runs end to end. Two agents from two different organizations can complete the handshake described in the previous sections, with no bilateral pre-registration, and arrive at a verified identity for the counterpart. The plumbing is sound.
The problem starts one layer up. When the agent's LLM is given sole control over the security procedure itself, things degrade in ways that are not a bug in the cryptography but a property of using a probabilistic component for a task that demands determinism. The evaluation of the prototypical implementation surfaces this clearly, and the failure modes are worth naming because they tell you exactly which parts of the design must not be left to the model.
The dialogue itself becomes an attack surface. When the verification logic is expressed as natural-language instructions in the system prompt, an attacker can shape the dialogue to push the model toward accepting a credential it should not accept. The model has been told to verify carefully, and it has also been told to be cooperative. A counterpart that frames its credentials persuasively, or that injects instructions disguised as part of the conversation, can shift the balance. The cryptographic check on the VC may pass while the policy check, if it lives in the prompt, gets argued away.
Selective disclosure leaks under pressure. The procurement agent in our scenario is supposed to present only the credentials relevant to the dialogue. When that selection is made by the LLM in response to the counterpart's requests, a sufficiently insistent counterpart can extract credentials that were not pertinent. The agent ends up over-disclosing, releasing claims that should have stayed in its store. The crypto did not fail. The model decided to share too much.
Trusted-issuer drift. The policy that says "I accept issuer X for claim type Y" is the entire foundation of differentiated trust. If that policy is encoded as text the model reads, and the model is asked to apply it across many turns and many dialogues, the application drifts. Issuers that should be authoritative for one claim type get treated as authoritative for another. Edge cases get resolved differently in successive runs. The policy stops being a policy and becomes a suggestion.
Revocation gets skipped. Revocation checks are unglamorous and easy to drop. A credential can be cryptographically valid and operationally dead at the same time. When the verification flow is orchestrated by the model, the revocation step is one of the first things to be quietly omitted, especially when the dialogue is long and the model is balancing many objectives. The result is that expired or revoked credentials get accepted because nobody actively checked.
The pattern across all of these is the same. The failure is not in DIDs, not in VCs, not in the ledger, not in the signatures. It is in the choice to put a probabilistic reasoner in charge of operations that need to be deterministic, auditable, and resistant to adversarial input from the very channel they are meant to protect.
The correct reading of the result is therefore not "this approach has problems." It is more specific. The approach works when the identity primitives sit in a deterministic security layer that the LLM can invoke as tools, and the approach degrades when the LLM is the one performing the verification reasoning. Resolving a DID, verifying a signature, checking a revocation status, evaluating whether an issuer is authoritative for a claim type, these are operations with right and wrong answers. They belong in code, behind a clean interface, with the model calling that interface and reading its boolean output. They do not belong inside the context window, expressed as guidance the model is asked to follow.
The design decisions this model forces you to make
If you take the previous section seriously, the architecture of an agent that uses DIDs and Verifiable Credentials looks different from a standard LLM agent with some auth bolted on. Specific decisions have to be made, and most of them are about drawing a hard line between what the model orchestrates and what runs deterministically beneath it.
The private key is not the LLM's problem. The key bound to the agent's DID is what makes the entire identity claim real. It must live in a component the LLM cannot read, a hardware security module, an enclave, or at minimum a local signing service exposed only as a tool. The model invokes a sign(payload) function and gets a signature back. It never sees the key material, never receives it as a string, never holds it in context. The same applies to any decryption keys tied to the DID. This is not paranoia. It is the only way to ensure that a prompt injection cannot exfiltrate the cryptographic identity of the agent.
The credential store is a managed asset, not a memory. The agent's portfolio of VCs has a lifecycle. Credentials get issued with validity periods. Some need to be revocable. Some need to be re-issued when a delegation changes. Treating the store as a static blob the model reads from is a path to expired credentials presented in production. The store should be a service with explicit operations: list available credentials, fetch a specific one, mark one as expired. A delegation VC that has aged past its validity is the new equivalent of a forgotten API key, and revocation has to be a real workflow, not an afterthought.
The trust policy is code, not a prompt. The list of issuers the agent accepts as authoritative for each claim type belongs in a deterministic policy engine. Open Policy Agent works. A purpose-built rules layer works. A handwritten module with explicit tests works. What does not work is putting the policy in the system prompt and asking the model to apply it. The policy needs to be versioned, reviewed, and auditable. Adding a new trusted issuer should be a code change, not a turn in a conversation.
DID method choice is not cosmetic. Different DID methods have different properties, and the choice has operational consequences. did:web is cheap and easy but ties resolution to DNS and HTTPS, which means the resolver inherits all the trust assumptions of the web PKI. did:key is fully self-contained but has no rotation story. Ledger-anchored methods like did:ion or did:ethr give real censorship resistance and clean rotation but add latency on resolution and operational complexity. For a procurement agent talking to many suppliers a day, the right answer is often a hybrid, with did:web for the agent itself for fast resolution and ledger-anchored DIDs for the issuers whose signatures must remain verifiable independently of any single domain.
Caching has to respect rotation. Resolving a DID Document at every first message adds latency that compounds across an agent that talks to many counterparts. Caching is the obvious answer. The non-obvious part is the TTL. Cache too long and a key rotation by the counterpart goes unnoticed, leaving the agent verifying signatures against a stale public key. Cache too short and the latency comes back. The TTL has to be coupled to the rotation cadence the issuers actually use, with explicit invalidation when a revocation event is observed.
A2A integration is a sequencing question. When the transport is A2A, the AgentCard is the natural place to publish the DID. The handshake then runs before the application-layer dialogue opens, and the first signed request after the handshake binds the session to the verified identity. Putting the verification step after the application messages have started is the wrong order, because by then the agent has already exposed intent and possibly data to a counterpart it has not yet authenticated. The discipline is simple: identity first, application second.
The conclusion the research arrives at, and the one to take away, is narrow and specific. Verifiable identity for agents works when the identity is enforced cryptographically outside the LLM and exposed to the LLM only through well-defined tools. The model orchestrates the dialogue, decides what to ask for, and reasons about the outcome. It does not perform the verification, does not hold the keys, and does not arbitrate the trust policy. That separation is what makes it possible for one agent to verify another at the very first message, across organizational boundaries, without anyone having registered anything in advance.




