A2A协议加上DID签名:无需事前注册也能认证Agent 🔐

摘要(3点)

✅ 在A2A Protocol的请求里加入DID签名,实现不依赖中心化注册表/不需要事前登记的Agent认证

✅ 同时支持两种信任模型:did:web(HTTPS信任)与did:ethr(区块链信任)

✅ 支持did:web与did:ethr之间的跨域(跨组织)认证

仓库/包地址

npm install a2a-did

1. 前言

本文将介绍如何在A2A协议中集成DID签名,实现无需中央注册的Agent认证方案。

A2A Protocol 正在成为AI Agent之间通信协议的一个热点选择。但真到落地实现时,往往会遇到几个现实问题。

Note:本文默认基于@a2a-js/sdk(A2A Protocol Specification v0.3.0兼容)。

1.1 OAuth的"事前注册成本"太高

如果希望每个Agent都有独立identity,那么每新增一个Agent,都需要先注册一个OAuth client_id。如果多个Agent共享同一个client_id,又会导致"到底是哪个Agent发的"无法区分。

1.2 对中央注册中心的依赖

谁来运营注册中心?如果注册中心挂了怎么办?如果不想把所有Agent都登记在中心系统怎么办?

1.3 跨域认证的困难

当不同组织的Agent之间通信时,如何验证对方的identity?

本文介绍使用**DID(Decentralized Identifier,去中心化标识符)**来解决这些问题的一种方法。将提供实际可运行的代码,让您可以立即尝试。

2. 快速开始(3分钟验证运行)

2.1 前提条件

  • Node.js 18以上
  • npm / pnpm / yarn

首先让我们运行起来。详细说明稍后再谈。

# 创建新项目
mkdir my-a2a-project
cd my-a2a-project
npm init -y

# 安装a2a-did
npm install a2a-did tsx

2.2 演示1执行(创建did:web identity)

创建demo1.ts

import { createAgentDIDService } from 'a2a-did';

async function main() {
  console.log('=== Creating DID:web Identity ===\n');

  const service = await createAgentDIDService(['web']);
  const identity = await service.createIdentity({
    method: 'web',
    agentId: 'my-agent',
    config: { type: 'web', domain: 'example.com' }
  });

  console.log('✓ Identity created successfully!\n');
  console.log('DID:', identity.did);
  console.log('Key ID:', identity.keyId);
  console.log('Private key length:', identity.privateKey.length, 'bytes');
}

main().catch(console.error);

运行:

npx tsx demo1.ts

期望输出

=== Creating DID:web Identity ===

✓ Identity created successfully!

DID: did:web:example.com:agents:my-agent
Key ID: did:web:example.com:agents:my-agent#key-1
Private key length: 32 bytes

3. 能做什么/不能做什么

3.1 ✅ 能做什么

  • 不依赖中心IdP的事前注册就能认证Agent(DID自主身份)
  • 可加密验证的认证(JWS签名)
  • 跨域Agent认证(跨组织通信)
  • 支持多种DID方法(did:web、did:ethr)

3.2 ❌ 不能做什么(超出范围)

3.2.1 委托(Delegation)

A2A社区正在讨论委托授权(delegated authorization),但那是"谁在代表谁"的证明层,和本文"认证层"分开。需要用VC(Verifiable Credentials)等另一个层解决。

3.2.2 细粒度访问控制(Fine-grained Access Control)

DID只能证明"你是谁",不解决"你能做什么"。工具/资源级权限属于Policy Engine范畴。

3.2.3 生产环境的额外工程

本库只提供认证层。生产落地还需要平台侧补齐:

  • 防重放攻击(iat/exp/jti校验)
  • DID Document缓存
  • 限流、监控

更多见:SECURITY.md

4. 为什么需要DID签名?

4.1 OAuth 2.0在"动态Agent"场景的痛点

  • 注册麻烦:新增Agent就要注册client
  • 不可扩展:100个Agent就是100次注册
  • 运行时动态生成难适配

4.2 中心化Registry的问题

  • 运维成本:谁来维护?
  • 单点故障(SPOF):挂了就全挂
  • 隐私/主权:不想把全部Agent都登记在中心系统

A2A社区也指出了这些问题,讨论了中央化Agent Registry的单点故障(SPOF)和审查风险等担忧。

4.3 DID签名的思路

给A2A消息加签名
↓
通过DID Document分发公钥
↓
校验签名 → 确认Agent的真实性

通过这个机制,可以减少对预注册和中央注册中心的依赖,实现Agent间的相互认证(作为基本认证层)。

注意:A2A规范中明确了Agent Card的签名步骤,但消息签名的标准字段尚未完善。本文重点介绍将消息签名作为协议扩展实现的方法。

5. 演示1:did:web签名→验证

5.1 什么是did:web

  • HTTPS信任模型:通过HTTPS分发公钥
  • 简单:有Web服务器就能使用
  • 用途:企业官方Agent、固定Endpoint

重要:did:web在生产环境中必须使用HTTPS。本地验证时请使用mkcert等准备HTTPS,或使用允许localhost例外的开发用resolver。

5.2 Step 1:创建DID Identity

// create-identity.ts
import { createAgentDIDService } from 'a2a-did';

// 初始化did:web service
const service = await createAgentDIDService(['web']);

// 为Agent创建DID
const identity = await service.createIdentity({
  method: 'web',
  agentId: 'my-agent',
  config: {
    type: 'web',
    domain: 'example.com'
    // port: 443 是默认值,可以省略
  }
});

console.log('DID:', identity.did);
// → did:web:example.com:agents:my-agent

要点

  • did:web使用HTTPS和DNS作为信任模型(利用现有Web基础设施)
  • DID Document放置位置:
    • did:web:example.comhttps://example.com/.well-known/did.json
    • did:web:example.com:agents:my-agenthttps://example.com/agents/my-agent/did.json
  • 生产环境中需安全保存privateKey(类型:Uint8Array)

5.3 Step 2:为A2A消息签名

// sign-message.ts
import { signA2AMessage } from 'a2a-did';

// 符合A2A Protocol的JSON-RPC消息
const message = {
  jsonrpc: '2.0',
  method: 'message/send',
  params: {
    message: {
      kind: 'message',
      messageId: 'msg-001',
      role: 'user',
      parts: [{ kind: 'text', text: 'Hello from Agent' }]
    }
  },
  id: 1
};

// 添加DID签名(JWS格式)
const jws = await signA2AMessage(message, identity);

// 发送带签名的请求
const request = { ...message, signature: jws };

注意signature字段不是A2A规范的标准字段,这里作为协议扩展添加。实际部署时,也可以用HTTP Header传(例如:Authorization: DIDAuth <jws>)。

5.4 Step 3:验证签名(接收端)

// verify-signature.ts
import { verifySignedA2ARequest } from 'a2a-did';

// Express/Fastify等端点
app.post('/a2a', async (req, res) => {
  if (req.body.signature) {
    const result = await verifySignedA2ARequest(req.body);

    if (!result.valid) {
      return res.json({
        jsonrpc: '2.0',
        error: { code: -32600, message: 'Invalid signature' },
        id: req.body.id
      });
    }

    console.log(`✅ Authenticated message from: ${result.senderDid}`);
  }

  // 正常的A2A处理...
});

这里发生了什么

  1. 从签名中提取发送者的DID
  2. 通过DID Resolution获取公钥
  3. 验证JWS签名
  4. 成功则result.senderDid中包含发送者的identity

6. 演示2:did:ethr实现动态Endpoint解析

如果你觉得did:web对DNS依赖太强,也可以试试用以太坊区块链的did:ethr

6.1 什么是did:ethr

  • 区块链信任模型:由以太坊管理
  • 可更新:可以后续更改Endpoint
  • 用途:动态Agent、跨域认证

6.2 设置

// ethr-setup.ts
import { createAgentDIDService } from 'a2a-did';

const service = await createAgentDIDService(['ethr']);

const identity = await service.createIdentity({
  method: 'ethr',
  agentId: 'blockchain-agent',
  config: {
    type: 'ethr',
    network: 'sepolia',  // 测试网
    rpcUrl: 'https://sepolia.infura.io/v3/YOUR_INFURA_KEY'
    // 可使用任何以太坊RPC端点(Infura、Alchemy等)
  }
});

console.log('DID:', identity.did);
// → did:ethr:sepolia:0x1234567890abcdef...

6.3 Agent Card解析流程

┌─────────────────┐
│ did:ethr:...    │
└────────┬────────┘
         │ 1. DID Resolution
         ↓
┌─────────────────────────┐
│ DID Document            │
│  {                      │
│    "service": [{        │
│      "type": "A2AAgentCard",│
│      "serviceEndpoint": │
│       "ipfs://Qm..."    │
│    }]                   │
│  }                      │
└────────┬────────────────┘
         │ 2. IPFS Fetch
         ↓
┌─────────────────────────┐
│ Agent Card              │
│  {                      │
│    "a2a_endpoint":      │
│     "https://agent.../a2a"│
│  }                      │
└─────────────────────────┘

6.4 访问Agent Card

// resolve-endpoint.ts
import { resolveA2AEndpoint } from 'a2a-did';

// 一步解析:DID → A2A endpoint
const endpoint = await resolveA2AEndpoint('did:ethr:sepolia:0x123...');
console.log('A2A Endpoint:', endpoint);
// → https://agent.example.com/a2a

// 现在可以通信了
await fetch(endpoint, {
  method: 'POST',
  body: JSON.stringify(signedMessage)
});

架构意图

did:ethr + IPFS + HTTPS的组合,是把身份与元数据(Agent Card)放在抗篡改更强的路径上,而通信本身仍走现实可用的HTTPS。这样能在"可验证"和"可运维"之间做平衡。

设计权衡:如果追求完全去中心化,通信层也应考虑libp2p等P2P协议。本文实现选择HTTPS endpoint,是更偏"工程现实解"。未来也可以把Agent Card里的endpoint扩展成P2P地址(如/ip4/.../tcp/.../p2p/...)。

6.5 did:web vs did:ethr 怎么选?

特性 did:web did:ethr
信任模型 HTTPS/TLS(Web PKI) 区块链
接入成本 低(只要HTTPS服务器) 中(需要RPC配置)
解析速度 快(HTTPS) 稍慢(RPC + IPFS)
抗篡改性 中(依赖HTTPS/DNS) 高(区块链)
运营成本 低(现有基础设施) 低(解析免费,创建·更新需Gas费)
推荐场景 企业Agent 动态Agent、跨域

7. 总结

本文介绍了为A2A Protocol添加DID签名的实现:

  • 无需中央注册即可进行Agent认证(基于DID的自主权型认证)
  • 密码学可验证的认证(JWS签名)
  • 可立即尝试的实现示例(did:web、did:ethr)
  • 可与现有A2A实现共存(可与@a2a-js/sdk并用)

7.1 全栈演示(将在下次文章中介绍)

a2a-did是核心库,为了展示"在实际应用中如何使用",正在准备全栈演示。

详情将在下次文章中介绍!

7.2 最后

如有任何问题欢迎反馈🙏

8. 参考资料


声明:本项目为实验性发布,仅供技术研究和学习使用。在生产环境使用前请充分测试,并遵守当地法律法规。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐