A-MAP Skill
A-MAP (Agent Mandate Protocol) gives AI agents cryptographic proof of what
they are authorized to do — and lets services verify that proof before acting.
Install
CODEBLOCK0
Part 1: Verify — Authenticate an Incoming Agent Request
Use this when another agent sends you a request and you need to confirm it
was authorized by a human before acting on it.
When to verify
- - A request includes
X-AMAP-Mandate, X-AMAP-Signature, X-AMAP-Timestamp,
X-AMAP-Nonce, or
X-AMAP-Agent-DID headers
- - You need to detect agent impersonation or replay attacks
- You need cryptographic proof of who authorized this agent to act
What you need
- - The five A-MAP headers from the incoming request
- The expected permission the caller claims to have
- The public keys of all agents in the chain (distribute out-of-band)
How to verify
CODEBLOCK1
Interpreting the result
On success (no error thrown):
- -
result.principal — the human who originally authorized this chain - INLINECODE6 — merged limits across all hops (e.g.
maxSpend: 347) - INLINECODE8 — array of verified links, one per hop
- INLINECODE9 — UUID for this verification event — log it for audit trail
On failure (AmapError thrown):
- -
err.code — specific error code (see references/error-codes.md) - INLINECODE13 — which link in the chain failed (0 = root), if applicable
Verify guardrails
- - Never proceed with an action if
verifyRequest() throws - Always log
result.auditId for audit trail - The default
InMemoryNonceStore does not work behind a load balancer —
use a shared store (Redis, Cloudflare KV) in multi-instance deployments
- - Always check
result.effectiveConstraints before consequential actions
(e.g. check
maxSpend before charging a card)
- - An
AmapError means the agent was not authorized, the request is a replay,
the chain was forged, or the identity is being spoofed — always reject
Part 2: Sign — Authenticate an Outgoing Request
Use this before calling any A-MAP-protected service to attach cryptographic
proof that a human authorized your action.
When to sign
- - You are calling a service that uses A-MAP to verify agents
- You need to prove a human authorized your action
- You are forwarding a delegation chain to a downstream service
Prerequisites
- - A mandate chain (from
amap.issue() or amap.delegate()) - Your agent's Ed25519 private key in INLINECODE22
How to sign
CODEBLOCK2
INLINECODE23 returns five headers ready to spread:
| Header | Content |
|---|
| INLINECODE24 | DID of the signing agent |
| INLINECODE25 |
Base64url-encoded DelegationToken chain |
|
X-AMAP-Signature | Ed25519 signature over canonical payload |
|
X-AMAP-Timestamp | ISO8601 UTC timestamp |
|
X-AMAP-Nonce | 128-bit random hex string (single-use) |
See references/signed-request-format.md for the full payload schema.
Sign guardrails
- - Never hardcode
AMAP_PRIVATE_KEY — always use an environment variable - Never log the private key
- A fresh nonce is generated on every
signRequest() call — never reuse headers - Check mandate expiry before signing — an expired mandate produces headers
the receiver will reject with
TOKEN_EXPIRED
Part 3: Delegate — Authorize a Sub-Agent
Use this when spawning a sub-agent that needs its own cryptographic proof of
authorization to call external services on your behalf.
When to delegate
- - You are spawning a sub-agent to handle part of a task
- A sub-agent needs to call A-MAP-protected services directly
- You want to limit what the sub-agent can do to a safe subset of your permissions
How to delegate
CODEBLOCK3
The sub-agent uses amap.signRequest({ mandateChain: subAgentChain, ... }) to
attach this chain to its outgoing requests.
Expiry strategy
| Task type | Recommended TTL |
|---|
| Single API call | INLINECODE34 |
| One-off task |
60s |
| Short workflow |
5m |
| Extended session | Match parent — SDK enforces the ceiling |
The three rules (enforced by SDK — see references/delegation-invariants.md)
- 1. Permissions can only narrow — you cannot grant what you do not have
- Constraints can only tighten — you cannot relax a limit set above you
- Expiry can only shorten — sub-agent tokens expire before yours
Delegate guardrails
- - Always pass
subAgentChain (full chain), not just the new token - Set the shortest possible
expiresIn for sub-agents - Log
childToken.tokenId for audit trail - Never share your
AMAP_PRIVATE_KEY — each agent has its own keypair
A-MAP 技能
A-MAP(代理授权协议)为AI代理提供其被授权执行操作的加密证明——并让服务在执行操作前验证该证明。
安装
npm install @agentmandateprotocol/core
第一部分:验证——认证传入的代理请求
当其他代理向你发送请求,且你需要在执行操作前确认该请求已获得人类授权时,使用此功能。
何时验证
- - 请求包含 X-AMAP-Mandate、X-AMAP-Signature、X-AMAP-Timestamp、X-AMAP-Nonce 或 X-AMAP-Agent-DID 标头
- 你需要检测代理冒充或重放攻击
- 你需要加密证明来确认谁授权了该代理执行操作
你需要准备
- - 传入请求中的五个A-MAP标头
- 调用者声称拥有的预期权限
- 链中所有代理的公钥(带外分发)
如何验证
javascript
import { amap, InMemoryNonceStore, LocalKeyResolver } from @agentmandateprotocol/core
const keyResolver = new LocalKeyResolver(new Map([
[did:amap:sender-agent:1.0:abc, process.env.SENDER_PUBKEY],
]))
// 生产环境中使用Redis或Cloudflare KV——参见防护措施
const nonceStore = new InMemoryNonceStore()
try {
const result = await amap.verifyRequest({
headers: {
X-AMAP-Agent-DID: request.headers[x-amap-agent-did],
X-AMAP-Mandate: request.headers[x-amap-mandate],
X-AMAP-Signature: request.headers[x-amap-signature],
X-AMAP-Timestamp: request.headers[x-amap-timestamp],
X-AMAP-Nonce: request.headers[x-amap-nonce],
},
method: request.method,
path: request.path,
body: request.body,
expectedPermission: book_flight,
keyResolver,
nonceStore,
})
// 安全执行操作
console.log(授权人:, result.principal)
console.log(有效限制:, result.effectiveConstraints)
console.log(审计ID:, result.auditId) // 始终记录此信息
} catch (err) {
// A-MAP在任何失败时都会抛出异常——从不返回 { valid: false }
console.error(授权失败: [${err.code}] ${err.message})
// 拒绝请求
}
解读结果
成功时(未抛出错误):
- - result.principal — 最初授权此链的人类
- result.effectiveConstraints — 所有跳转的合并限制(例如 maxSpend: 347)
- result.chain — 已验证的链接数组,每跳一个
- result.auditId — 此验证事件的UUID——记录用于审计追踪
失败时(抛出 AmapError):
- - err.code — 特定错误代码(参见 references/error-codes.md)
- err.hop — 链中失败的链接(0 = 根节点),如适用
验证防护措施
- - 如果 verifyRequest() 抛出异常,切勿继续执行操作
- 始终记录 result.auditId 用于审计追踪
- 默认的 InMemoryNonceStore 在负载均衡器后无法工作——在多实例部署中使用共享存储(Redis、Cloudflare KV)
- 在执行重要操作前始终检查 result.effectiveConstraints(例如在扣款前检查 maxSpend)
- AmapError 表示代理未获授权、请求是重放攻击、链被伪造或身份被冒充——始终拒绝
第二部分:签名——认证传出请求
在调用任何受A-MAP保护的服务之前使用此功能,以附加人类授权你执行操作的加密证明。
何时签名
- - 你正在调用使用A-MAP验证代理的服务
- 你需要证明人类授权了你的操作
- 你正在将授权链转发给下游服务
前提条件
- - 授权链(来自 amap.issue() 或 amap.delegate())
- 你的代理的Ed25519私钥,存储在 AMAPPRIVATEKEY 中
如何签名
javascript
import { amap } from @agentmandateprotocol/core
const headers = amap.signRequest({
mandateChain: myMandateChain,
method: POST,
path: /api/book-flight,
body: JSON.stringify(requestBody), // 如果没有请求体则省略
privateKey: process.env.AMAPPRIVATEKEY,
})
await fetch(https://api.example.com/book-flight, {
method: POST,
headers: { Content-Type: application/json, ...headers },
body: JSON.stringify(requestBody),
})
amap.signRequest() 返回五个可直接使用的标头:
| 标头 | 内容 |
|---|
| X-AMAP-Agent-DID | 签名代理的DID |
| X-AMAP-Mandate |
Base64url编码的DelegationToken链 |
| X-AMAP-Signature | 规范负载的Ed25519签名 |
| X-AMAP-Timestamp | ISO8601 UTC时间戳 |
| X-AMAP-Nonce | 128位随机十六进制字符串(一次性使用) |
完整负载模式参见 references/signed-request-format.md。
签名防护措施
- - 切勿硬编码 AMAPPRIVATEKEY——始终使用环境变量
- 切勿记录私钥
- 每次调用 signRequest() 都会生成新的nonce——切勿重复使用标头
- 在签名前检查授权是否过期——过期的授权会产生接收方将以 TOKEN_EXPIRED 拒绝的标头
第三部分:委托——授权子代理
在生成需要自身加密授权证明以代表你调用外部服务的子代理时使用此功能。
何时委托
- - 你正在生成子代理来处理部分任务
- 子代理需要直接调用受A-MAP保护的服务
- 你想将子代理的操作限制在你权限的安全子集内
如何委托
javascript
import { amap } from @agentmandateprotocol/core
// myToken = 你收到的DelegationToken;myChain = 包含myToken的完整链
let childToken
try {
childToken = await amap.delegate({
parentToken: myToken,
parentChain: myChain,
delegate: did:amap:sub-agent:1.0:xyz,
permissions: [charge_card], // 必须是myToken.permissions的子集
constraints: { maxSpend: 347 }, // 只能收紧,不能放宽
expiresIn: 15m, // 不能超过父级剩余的TTL
privateKey: process.env.AMAPPRIVATEKEY,
})
} catch (err) {
// 如果违反不变性条件,AmapError会在签名前抛出:
// PERMISSION_INFLATION — 权限不在父级中
// CONSTRAINT_RELAXATION — 约束比父级宽松
// EXPIRY_VIOLATION — TTL超过父级剩余时间
throw err
}
// 将完整链传递给子代理——而不仅仅是子令牌
const subAgentChain = [...myChain, childToken]
子代理使用 amap.signRequest({ mandateChain: subAgentChain, ... }) 将此链附加到其传出请求中。
过期策略
60s |
| 短工作流 | 5m |
| 扩展会话 | 匹配父级——SDK强制执行上限 |
三条规则(由SDK强制执行——参见 references/delegation-invariants.md)
- 1. 权限只能缩小——你不能授予自己没有的权限
- 约束只能收紧——你不能放宽上级设定的限制
- 过期时间只能缩短——子代理令牌在你之前过期
委托防护措施
- - 始终传递 subAgentChain(完整链),而不仅仅是新令牌
- 为子代理设置尽可能短的 expiresIn
- 记录 childToken.tokenId 用于审计追踪
- 切勿共享你的 AMAPPRIVATEKEY——每个代理都有自己的密钥对