# HETA Agent Identity 接入指南

- Contract Version: 2.0
- Updated: 2026-09-07
- Audience: Agent 运行方及接入业务的编程 Agent
- Repository Source: `apps/agent-identity/docs/integration/agent-identity-agent-guide.md`
- 决定依据：根 ADR-0015

V2 由员工自助生成 Agent Key，Agent 自动换取身份凭证，业务验证 Agent 和所属员工后独立授权。它是对 V1 私钥断言、人工 Execution 和 Target Grant 流程的破坏性替代。旧凭据不能自动转换为 Key，旧换证端点不再签发。

## 0. 运行实例值（由服务生成）

```dotenv
runtime_deployed=true
deployment_available=true
deployment_environment=simulation
identity_verification_mode=live
real_end_to_end_verified=false
AGENT_IDENTITY_ISSUER=https://agent-id.staging.hetapet.com
AGENT_IDENTITY_DEPLOYMENT_ENVIRONMENT=simulation
AGENT_IDENTITY_PARENT_VERIFICATION_MODE=live
AGENT_IDENTITY_PARENT_ISSUER=https://workforce-id.staging.hetapet.com
AGENT_IDENTITY_RESOURCE_AUDIENCES=["https://tl.hetapet.cn/api/agent"]
AGENT_IDENTITY_OAUTH_METADATA_URL=https://agent-id.staging.hetapet.com/.well-known/oauth-authorization-server
AGENT_IDENTITY_AGENT_GUIDE_URL=https://agent-id.staging.hetapet.com/docs/agent-identity-agent-guide.md
```

`runtime_deployed=true` 与 `deployment_available=true` 只表示当前实例已经运行且能够发布契约和协议端点，不表示目标业务已完成端到端验收。部署环境和父级身份核验模式来自当前实例的显式配置，不从 hostname、Issuer 或父级类型推断。

## 1. 接入边界与输入

完整读取本指南、门户身份路由及目标仓库约定。企业成员浏览器登录选择 Workforce，Agent 自身认证选择 Agent Identity，普通机器或系统调用按门户路由移交外部系统治理。

| 输入 | 来源与含义 |
| --- | --- |
| Agent Issuer | 当前部署值，精确 HTTPS Origin |
| Metadata | `${issuer}/.well-known/oauth-authorization-server` |
| 业务 Audience | 当前 Metadata 已配置列表中的本业务精确标识 |
| 预期父级 Issuer | 当前实例唯一信任的 Workforce Issuer |
| Agent Key | 所属员工在个人控制台生成后交付对应 Agent 运行方 |
| 本地员工映射及授权规则 | 业务自行拥有和维护 |

同一员工可为不同 Agent 生成不同 Key。Agent 始终只有一个不可变员工父级，以 `(parent_kind, parent_issuer, parent_subject)` 引用；不按名字、邮箱或手机号映射员工。不同 Issuer 下的相同 ID 不表示同一身份。一个实例只信任一个父级身份域，Customer 和 System Principal 不在本契约内。

## 2. 员工生成与管理 Key

员工从 User Center 的“员工登录”或“我的 Agent”进入本域个人控制台，通过 Workforce 完成企业成员登录。填写 Agent 名称和 1 至 90 天有效期（默认 90 天），即可生成独立 Key，不再上传公钥或创建 Execution。

完整 Key 仅成功创建或轮换时展示一次，丢失后需生成新 Key。轮换保留 Agent ID 和员工归属，立即停止旧 Key 的新换证；撤销 Key 后可为原 Agent 重新生成。停用 Agent 会终止其 Key，不能继续轮换或恢复。列表只显示 Key 标识、前缀、期限、状态和最近成功换证时间。

Key 仅通过安全方式交付对应 Agent 的受保护运行环境。不能提交源码、记录日志、放入 URL、浏览器持久化或发给业务服务。User Center 服务端仅保存 Key 摘要；用于持续核验员工的 Workforce 专用状态凭据只由 Agent Identity 加密保存，不能交给运行方。

退出控制台、原管理会话到期或服务重启不撤销 Key。员工失效会阻止新身份凭证；身份来源故障时失败关闭，不使用本地旧 active 缓存。

## 3. Metadata 与自动换证

从 Metadata 取得端点并验证 `issuer` 精确匹配配置，`contract_version` 为 `2.0`，Token/JWKS/文档端点均与配置 Issuer 同源。凭据请求不跟随重定向。Metadata 不是 OIDC 人类登录 Discovery。

Metadata 公告专用扩展 Grant `urn:heta:params:oauth:grant-type:agent-key`、认证方法 `agent_key`、签名算法 `RS256` 以及 `resource_audiences_supported`。新增业务由部署方显式配置其 Audience；配置不是授予业务权限，也不限制 Key 只能属于某项业务。

Agent 向 Metadata 的 `token_endpoint` 请求：

```http
POST /oauth/agent-token
Authorization: Bearer <agent_key>
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aheta%3Aparams%3Aoauth%3Agrant-type%3Aagent-key&audience=<url_encoded_business_audience>
```

表单只接受单个 `grant_type` 与单个 `audience`；不能附加员工、权限、Execution 或 Client Assertion。凭据只通过 Authorization Header 提交。服务端检查 Key、Agent、期限和员工当前身份；异步核验及签名后再次检查本地状态。

成功返回 `200` 和 `Cache-Control: no-store`：

```json
{"access_token":"<signed_agent_identity_jwt>","token_type":"Bearer","expires_in":300}
```

实际有效期取 `expires_in` 和 JWT `exp`，不硬编码为固定五分钟。接近 Key 到期时可能更短。Agent 可以在凭证即将到期时自动换取新的凭证，员工不需要重复登录或创建执行记录。短期凭证仅提交给其绑定的业务 Audience，业务端不接收原始 Agent Key。

## 4. 业务验签与身份映射

优先复用维护良好的 JWT/JWKS 库。每次受保护请求至少验证：

- 签名为 Metadata 所述的 RS256，密钥来自经过验证的 `jwks_uri`，`kid` 匹配；
- Header `typ` 为 `at+jwt`，`iss` 完全匹配当前 Agent Issuer；
- `aud` 为单个字符串，完全匹配本业务 Audience；
- `iat`、`exp` 为有效整数，尚未到期，签发跨度不超过 300 秒；
- `token_use` 精确为 `agent_identity`；
- `sub`、`credential_id`、`jti` 为非空字符串；
- `parent_kind` 精确为 `human`，`parent_issuer` 精确匹配已配置 Workforce，`parent_subject` 为非空字符串。

可使用不超过五秒时钟容差，不能无限延长有效期。禁止只解码 JWT、根据网络来源信任身份、将旧 V1 凭证视为 V2 或把 Agent 凭证当成员登录 Token。身份验证失败返回 `401`；身份有效但业务拒绝返回 `403`。

经验证后保留两组独立身份：Agent actor 为 `(iss, sub)`，员工身份为 `(human, parent_issuer, parent_subject)`。`credential_id` 标记具体 Key，轮换不改变 actor。`jti` 用于请求关联和审计，不表示一次人工 Execution；同一短期凭证可以在期限内复用，业务写操作的幂等与重放规则由业务自身处理。

Node.js 业务端示例（端点先从经过验证的 Metadata 取得）：

```javascript
import { createRemoteJWKSet, jwtVerify } from "jose";
const keys = createRemoteJWKSet(new URL(metadata.jwks_uri));

async function verifyAgentIdentity(token) {
  const { payload } = await jwtVerify(token, keys, {
    issuer: configuredAgentIssuer,
    audience: configuredBusinessAudience,
    algorithms: ["RS256"], typ: "at+jwt", maxTokenAge: "5m", clockTolerance: 5,
    requiredClaims: ["sub", "iat", "exp", "jti", "credential_id", "token_use", "parent_kind", "parent_issuer", "parent_subject"]
  });
  if (payload.aud !== configuredBusinessAudience || payload.token_use !== "agent_identity"
    || payload.parent_kind !== "human" || payload.parent_issuer !== configuredWorkforceIssuer
    || !Number.isInteger(payload.iat) || !Number.isInteger(payload.exp)
    || payload.exp - payload.iat > 300
    || [payload.sub, payload.jti, payload.credential_id, payload.parent_subject]
      .some((value) => typeof value !== "string" || !value)) {
    throw new Error("Invalid Agent identity");
  }
  return {
    actor: { issuer: payload.iss, subject: payload.sub },
    parent: { kind: payload.parent_kind, issuer: payload.parent_issuer, subject: payload.parent_subject },
    credentialId: payload.credential_id, proofId: payload.jti
  };
}
```

这个函数只验证身份。调用方还必须用返回的权威键找到已确认的本地映射，并执行本业务对成员、Agent、操作和资源的当前授权规则；没有授权规则或稳定映射时拒绝业务调用，不能自动赋予成员角色或全部员工权限。

## 5. 业务职责与撤销

业务自行决定账号资格、是否接纳 Agent、操作与资源权限、数据范围、人工触发要求、审批及二次确认。Key 有效、员工 active 或 Audience 已配置均不是业务许可。业务的任务和 Execution 如有需要，由业务自己创建、约束和审计，身份中心不拥有任务内容。

Key 到期或撤销、Agent 停用、员工失效立即阻止新的凭证签发。已签发短期凭证的身份撤销传播窗口最多五分钟；业务每次请求执行自身当前授权，因此本业务撤权可以立即生效。需要更严格即时身份撤销的业务必须先确认额外契约，不能声称离线验签能即时发现远端 Key 撤销。

业务审计分别记录 Agent actor、员工权威键、Key/凭证标识、操作、资源、结果和业务关联。身份审计记录登记、凭证生命周期与签发事件；两端均不得保存原始 Key、JWT、父级状态凭据或完整 Authorization Header。

## 6. 错误与升级

| 场景 | 结果 | 接入方处理 |
| --- | --- | --- |
| 无效、到期、撤销的 Key，或父级授权失效 | `401 invalid_agent_key` | 停止使用，请本人在控制台检查或生成新 Key |
| 表单缺失、重复或包含额外字段 | `400 invalid_request` | 修正请求 |
| 完整表单使用不支持的 Grant | `400 unsupported_grant_type` | 使用当前 Metadata 与契约 |
| 业务 Audience 未配置或不匹配 | `400 invalid_target` | 核对本业务标识及部署配置，不自行替换目标 |
| 员工状态源或状态协议暂不可用 | `503 PARENT_STATUS_UNAVAILABLE` | 当前失败关闭，有限重试，不回退旧登录凭据 |
| 管理会话缺失或过期 | `401 PARENT_SESSION_REQUIRED` | 员工重新登录控制台 |
| 管理 CSRF 无效、员工已失效 | `403` | 终止写操作 |
| 管理的 Agent 不属于当前员工 | `404 AGENT_NOT_FOUND` | 不枚举或尝试其他员工 ID |
| 轮换期间 Agent/Key 已改变 | `409 AGENT_KEY_CHANGED` | 刷新状态后重新决定 |
| 调用旧 `/oauth/execution-token` | `410 agent_contract_upgraded` | 按 V2 更新，不能继续使用旧断言 |

升级保留 Agent ID、归属和历史审计。旧登记最初没有 V2 Key，由本人登录生成；旧私钥、Execution 与 Target Grant 不自动迁移成凭据或业务许可。旧业务必须更新验证契约后才能消费 V2。发布与回滚以本域 Runbook 为准，不能让旧代码直接读取新数据库。

## 7. 验收与交付

通过目标业务的公开接口验证有效签名和身份映射、错误签名/Issuer/Audience/用途/期限拒绝、身份有效但无业务权限拒绝、业务撤权立即生效、Key 轮换/撤销/到期和员工失效阻止新换证，并确认两端审计区分 actor 与员工且没有凭据明文。

员工侧验证本人登录、生成和轮换 Key、其他员工不可见及不可操作、退出浏览器和重启后仍可换证。真实员工登录、身份服务验收与真实业务端到端验收分别报告；测试替身或测试业务通过不能把真实业务 `real_end_to_end_verified` 改为 true。

交付报告列出选定身份域、实际 Issuer/Audience、实现文件、实际运行检查、部署状态、真实员工验收与真实业务验收结果，以及尚缺的业务映射或授权配置。应用级登记、外部修改和部署必须处于用户授权范围内。
