
# WIF 参考

Workload Identity Federation 的环境变量、验证规则、配置文件配置和错误参考。

---

本页汇集了 [Workload Identity Federation](/docs/en/manage-claude/workload-identity-federation) 的配置界面、验证约束和错误映射。有关设置指南，请参阅[提供商指南](/docs/en/manage-claude/workload-identity-federation#identity-providers)。

## 令牌交换请求

`POST /v1/oauth/token` 接受使用 [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523) `jwt-bearer` 授权的 JSON 请求体。SDK 根据以下[环境变量](#环境变量)为您构建此请求；每个提供商指南中的 cURL 示例展示了原始请求体。

| 字段 | 必填 | 描述 |
| :--- | :--- | :--- |
| `grant_type` | 是 | 始终为 `urn:ietf:params:oauth:grant-type:jwt-bearer`。 |
| `assertion` | 是 | 您的身份提供商签发的 OIDC JWT。 |
| `federation_rule_id` | 是 | 要评估的联合规则的标签 ID（`fdrl_...`）。 |
| `organization_id` | 是 | 您的 Anthropic 组织的 UUID。 |
| `service_account_id` | 是 | 目标服务账户的标签 ID（`svac_...`）。 |
| `workspace_id` | 条件性 | 铸造令牌所作用域的工作空间的标签 ID（`wrkspc_...`），或使用字面量 `default` 表示组织的默认工作空间。当规则启用于多个工作空间时必填。省略时，服务器选择规则唯一启用的工作空间。 |

## 令牌交换响应

`POST /v1/oauth/token` 返回标准的 OAuth 2.0 令牌响应（[RFC 6749 §5.1](https://www.rfc-editor.org/rfc/rfc6749#section-5.1)）：

| 字段 | 类型 | 描述 |
| --- | --- | --- |
| `access_token` | string | 短期 Anthropic 令牌，前缀为 `sk-ant-oat01-...`。作为 `Authorization: Bearer <token>` 传递。 |
| `token_type` | string | 始终为 `Bearer`。 |
| `expires_in` | integer | 令牌过期前的秒数。 |
| `scope` | string | 匹配规则授予的 OAuth 作用域。 |

## 环境变量

SDK 读取这些变量以在无构造函数参数的情况下执行联合令牌交换。

| 变量 | 必填 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| `ANTHROPIC_FEDERATION_RULE_ID` | 是 | 要评估的联合规则的标签 ID。 | `fdrl_...` |
| `ANTHROPIC_ORGANIZATION_ID` | 是 | 您的 Anthropic 组织的 UUID。在 Claude Console 的 **Settings > Organization** 中查找。 | `00000000-0000-0000-0000-000000000000` |
| `ANTHROPIC_IDENTITY_TOKEN_FILE` | `_TOKEN_FILE` 或 `_TOKEN` 二选一 | 您的身份提供商 (IdP) 签发的 JWT 的文件系统路径。SDK 在每次交换时重新读取此文件，以便在磁盘上轮换的预测令牌始终保持最新。 | `/var/run/secrets/anthropic.com/token` |
| `ANTHROPIC_IDENTITY_TOKEN` | `_TOKEN_FILE` 或 `_TOKEN` 二选一 | JWT 的字面量字符串。当您的平台将令牌作为环境变量而非文件注入时使用。 | `eyJhbGciOiJSUzI1NiIs...` |
| `ANTHROPIC_SERVICE_ACCOUNT_ID` | 是 | 签发的访问令牌所代表的目标 Anthropic 服务账户的标签 ID。 | `svac_...` |
| `ANTHROPIC_WORKSPACE_ID` | 条件性 | 铸造令牌所作用域的工作空间的标签 ID，或使用字面量 `default`。当联合规则启用于多个工作空间时必填；当规则绑定到单个工作空间时可选。铸造的令牌在交换时作用域为该工作空间，因此切换工作空间需要新的交换。 | `wrkspc_...` |
| `ANTHROPIC_PROFILE` | 否 | 要加载的[配置文件](#配置文件)的名称。优先于此表中的联合环境变量。 | `staging-profile` |

直接的环境变量联合路径仅在 `ANTHROPIC_FEDERATION_RULE_ID`、`ANTHROPIC_ORGANIZATION_ID`、`ANTHROPIC_SERVICE_ACCOUNT_ID` 和 `ANTHROPIC_IDENTITY_TOKEN_FILE` 或 `ANTHROPIC_IDENTITY_TOKEN` 之一全部设置时激活。`ANTHROPIC_WORKSPACE_ID` 一同读取但不控制激活。

<Warning>
设置为空字符串的变量仍然占据凭据优先级链中的位置。如果导出了 `ANTHROPIC_API_KEY=""`，SDK 会选择带有空密钥的 API 密钥路径而非回退到联合。请取消设置未使用的凭据变量而非将其置空。
</Warning>

### 凭据优先级

SDK 按以下顺序解析凭据。第一个产生凭据的来源胜出。

| 顺序 | 来源 | 说明 |
| :--- | :--- | :--- |
| 1 | 构造函数参数（`api_key=`、`auth_token=`、`credentials=`） | 始终覆盖其他所有来源。 |
| 2 | `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN` | 完全遮蔽联合。从 API 密钥迁移时请取消设置这些变量。 |
| 3 | `ANTHROPIC_PROFILE` | 加载 `<config_dir>/configs/<name>.json`。命名配置文件缺失是错误，不会回退。 |
| 4 | 联合环境变量 | `ANTHROPIC_FEDERATION_RULE_ID` + `ANTHROPIC_ORGANIZATION_ID` + `ANTHROPIC_SERVICE_ACCOUNT_ID` + `ANTHROPIC_IDENTITY_TOKEN[_FILE]`。 |
| 5 | 活动配置文件 | 通过 `<config_dir>/active_config` 解析，回退到名为 `default` 的配置文件。 |

当加载配置文件时，环境变量填充配置文件省略的字段，但从不覆盖配置文件显式设置的字段。例如，`ANTHROPIC_WORKSPACE_ID` 仅在活动配置文件未设置它时填充 `workspace_id`。

## 配置文件

配置文件是 SDK 和 `ant` CLI 都读取的命名配置文件。配置文件让您可以将联合参数随容器镜像一起部署，或在不更改代码的情况下切换环境。

### 配置目录

SDK 按以下顺序定位配置目录：

1. `$ANTHROPIC_CONFIG_DIR`
2. Linux 和 macOS 上的 `~/.config/anthropic`
3. Windows 上的 `%APPDATA%\Anthropic`

### 活动配置文件

活动配置文件名称按以下顺序解析：

1. `$ANTHROPIC_PROFILE`
2. `<config_dir>/active_config` 的内容（由 `ant profile activate <name>` 写入的单行文件）
3. 字面量名称 `default`

Claude Code 和 Claude Agent SDK 遵循相同的解析顺序，因此在此处配置的联合配置文件也无需额外设置即可认证这些工具。

### 文件布局

| 路径 | 内容 | 敏感性 |
| :--- | :--- | :--- |
| `<config_dir>/configs/.json` | `version`、`authentication` 块、`organization_id`、`workspace_id` 和 `base_url`。 | 非密。可安全提交或烘焙到镜像中。 |
| `<config_dir>/credentials/.json` | `version`、缓存的 `access_token`、`expires_at` 和（用于交互式登录）`refresh_token`。 | 密钥。由 SDK 以 `0600` 权限写入。 |

配置文件和凭据文件都携带顶层字符串 `version` 字段，格式为 `major.minor`（当前为 `"1.0"`）。SDK 自动写入此字段，以便未来版本可以检测和迁移旧格式；手动创建配置时省略它，SDK 会将文件视为当前版本。

### 联合配置文件示例

```json configs/production.json
{
  "version": "1.0",
  "authentication": {
    "type": "oidc_federation",
    "federation_rule_id": "fdrl_...",
    "service_account_id": "svac_...",
    "identity_token": {
      "source": "file",
      "path": "/var/run/secrets/anthropic.com/token"
    }
  },
  "organization_id": "00000000-0000-0000-0000-000000000000",
  "workspace_id": "wrkspc_...",
  "base_url": "https://api.anthropic.com"
}
```

如果省略 `authentication.identity_token`，SDK 回退到环境中的 `ANTHROPIC_IDENTITY_TOKEN_FILE` 或 `ANTHROPIC_IDENTITY_TOKEN`。

## OAuth 作用域

您在联合规则上设置的 `oauth_scope` 决定了铸造的访问令牌可以调用哪些 Claude API 端点。

| 作用域 | 授予访问权限 |
| :--- | :--- |
| `workspace:developer` | 规则工作空间中的所有非管理性 Claude API 端点：[Messages](/docs/en/api/messages)（包括流式传输和 token 计数）、[Models](/docs/en/api/models-list)、[Managed Agents](/docs/en/managed-agents/overview) 及其会话、[Files](/docs/en/build-with-claude/files) 和 [Skills](/docs/en/build-with-claude/skills-guide)。这与为同一工作空间签发的 API 密钥的访问权限相同。 |
| `org:manage_tunnels` | [MCP 隧道 API](/docs/en/agents-and-tools/mcp-tunnels/reference#tunnels-api)：列出和获取隧道、注册和归档 CA 证书、显示和轮换隧道令牌、归档隧道。Console 的创建隧道模态框在您从中创建规则时锁定此作用域。 |

对令牌作用域之外的端点的请求返回 HTTP 403。目前不提供更细粒度的作用域（按资源或读写区分）。

## 验证规则

Anthropic 在您创建或更新发行方和规则时，以及在交换时验证传入 JWT 时，强制执行这些约束。

### 资源字段

| 字段 | 约束 |
| :--- | :--- |
| 发行方、规则和服务账户 `name` | 必须匹配 `^[a-z0-9-]+$`，长度 1 到 255 个字符。 |
| `workspace_id` | 可选。其配额、计费和速率限制适用于此规则下铸造的令牌的工作空间（`wrkspc_...`）。必须是同一组织中的工作空间，且目标服务账户必须是该工作空间的成员。对于仅配置了一个工作空间的规则可以省略。 |
| `token_lifetime_seconds` | `60` 到 `86400` 之间的整数（1 分钟到 24 小时）。默认 `3600`。超出此范围的值在请求时被拒绝。参见[令牌有效期和刷新](/docs/en/manage-claude/workload-identity-federation#token-lifetime-and-refresh)。 |

### URL 字段

`issuer_url`、`jwks.discovery_base` 和 `jwks.url` 字段经过验证：

| 约束 | 详情 |
| :--- | :--- |
| 协议 | 必须为 `https`。 |
| 端口 | 必须为 `443`（显式或默认）。 |
| 主机 | 必须是您的 OIDC 提供商的公共 DNS 主机名。必须解析为公共 IP 地址；不接受 IP 字面量。 |

URL 验证失败返回 `400 invalid_request_error`，错误消息前缀为字段名（例如 `issuer_url: url must use https scheme`）。

<Note>
URL 约束仅适用于 Anthropic 拨号的 URL。在 `explicit_url` 和 `inline` JWKS 模式下，以及在设置了 `jwks.discovery_base` 的 `discovery` 模式下，`issuer_url` 作为字符串与 JWT `iss` 声明进行比较，永远不会被获取，因此可以引用内部主机名或非标准端口。
</Note>

### JWT 验证

| 约束 | 详情 |
| :--- | :--- |
| 最大大小 | `assertion` JWT 最大 16 KiB。 |
| 签名算法 | 仅接受非对称算法（RSA 和 ECDSA 系列：ES256、ES384、ES512、RS256、RS384、RS512、PS256、PS384、PS512）。拒绝 HMAC（`HS256`、`HS384`、`HS512`）和 `none`。 |
| 密钥 ID | JWT 头必须携带与发行方 JWKS 中密钥匹配的 `kid`。没有 `kid` 的令牌被拒绝。 |
| 必需声明 | `sub` 必须存在。`iat` 必须存在且不在未来。`exp` 必须存在且在未来。 |
| 最大有效期 | 令牌的有效期（`exp` 减 `iat`）不得超过发行方配置的最大值（默认 1 小时，可在 Claude Console 中为每个发行方配置）。 |
| 时钟偏差 | 对 `exp`、`nbf` 和 `iat` 应用 30 秒的容差。 |

## 规则匹配语义

联合规则的 `match` 块决定传入的 JWT 是否被接受。所有已填充的字段使用 AND 语义评估：JWT 必须满足每个已填充的匹配器。至少必须设置 `subject_prefix`、`claims` 或 `condition` 之一；仅包含 `audience`（或没有任何匹配器）的 `match` 块被拒绝。这可以防止规则接受来自发行方的每个令牌。

| 匹配器 | 类型 | 语义 |
| :--- | :--- | :--- |
| `subject_prefix` | string | 对 JWT `sub` 声明的精确匹配。尾部 `*` 使其成为前缀匹配（`sub` 值必须以 `*` 之前的字符开头）。区分大小写。 |
| `audience` | string | JWT `aud` 声明必须包含此精确字符串。当 `aud` 是数组时，任何精确匹配的元素都满足检查。 |
| `claims` | map\<string, string\> | 每个键是顶层声明名称，每个值是所需的精确字符串值。对于嵌套、数字、布尔或复杂声明（如列表和映射），请改用带有 CEL 表达式的 `condition`。 |
| `condition` | string (CEL) | 必须评估为 `true` 的 [CEL](https://cel.dev/) 表达式。 |

### CEL 评估环境

`condition` 表达式可以访问一个变量：

| 变量 | 类型 | 内容 |
| :--- | :--- | :--- |
| `claims` | map | 完整的解码后 JWT 声明集。嵌套对象可作为嵌套映射访问。 |

示例：

```text
claims.sub.startsWith("repo:acme-corp/") && claims.ref in ["refs/heads/main", "refs/heads/release"]
```

<Warning>
CEL 条件是安全边界。对超出预期的更多输入评估为 `true` 的表达式会授予超出预期的更广泛访问权限。当静态匹配器能表达您的约束时，请优先使用它们。
</Warning>

## 错误

### 令牌交换错误

`POST /v1/oauth/token` 以标准 [API 错误格式](/docs/en/api/errors)返回错误。SDK 将交换失败包装在类型化的 `FederationExchangeError`（或语言等效类型）中，暴露 HTTP 状态、响应体和 `request_id`。

| 状态 | 错误 | 原因 | 解决方案 |
| :--- | :--- | :--- | :--- |
| 400 | `invalid_request` | `federation_rule_id` 格式错误或缺少必需的请求字段。 | 验证 `fdrl_` ID 以及请求体是否包含所有必需字段。 |
| 400 | `invalid_request` | `workspace_id_required`：联合规则启用于多个工作空间，但请求中省略了 `workspace_id`。 | 将 `ANTHROPIC_WORKSPACE_ID`（或原始请求的 `workspace_id` 请求体字段）设置为您希望令牌作用域的 `wrkspc_...` ID。参见[令牌交换请求](#令牌交换请求)。 |
| 400 | `invalid_grant` | JWT `iss` 声明不完全等于注册的 `issuer_url`。 | 逐字节比较，包括尾部斜杠和协议：`jq -rR 'split(".")[1] \| gsub("-";"+") \| gsub("_";"/") \| @base64d \| fromjson \| .iss' <<< "$JWT"`。 |
| 400 | `invalid_grant` | JWKS 获取失败、JWKS 过时，或 JWT 使用不在 JWKS 中的密钥签名。 | 对于 `inline` 模式，使用轮换后的密钥更新发行方。对于 `discovery` 和 `explicit_url`，确认 JWKS 端点在端口 443 上可达；如果发行方最近轮换了签名密钥，请参见[密钥轮换和缓存](#密钥轮换和缓存)。 |
| 400 | `invalid_grant` | JWT `exp` 声明已过期（超出 30 秒偏差窗口）。 | 确认您的身份提供商正在投影新鲜令牌且 SDK 正在重新读取令牌文件。 |
| 400 | `invalid_grant` | JWT 已验证但其声明不满足规则的 `match` 块。 | 解码 JWT 并将每个声明与规则进行比较。`subject_prefix` 区分大小写。`audience` 需要精确的元素匹配。 |
| 400 | `invalid_grant` | `federation_rule_id` 不存在、已归档，或 JWT 未被授权使用它（合并以防止枚举）。 | 在 Claude Console 中确认规则 ID 以及规则未被归档。 |

所有 `invalid_grant` 失败返回 HTTP 400；具体原因仅在服务器端记录，不暴露在响应中。

### 常见 SDK 端故障

| 症状 | 原因 | 解决方案 |
| :--- | :--- | :--- |
| SDK 报告"无凭据"而非进行交换 | `ANTHROPIC_FEDERATION_RULE_ID`、`ANTHROPIC_ORGANIZATION_ID`、`ANTHROPIC_SERVICE_ACCOUNT_ID` 或 `ANTHROPIC_IDENTITY_TOKEN[_FILE]` 之一未设置且无活动配置文件。 | 设置所有四个变量，或配置一个配置文件。 |
| SDK 使用 API 密钥认证而非联合 | 设置了 `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN` 且在优先级中胜出。 | 取消设置密钥或令牌变量。 |
| 首次请求时出现 `FileNotFoundError` | `ANTHROPIC_IDENTITY_TOKEN_FILE` 中的路径不存在。SDK 在交换时惰性打开文件。 | 确认预测令牌卷已挂载且路径匹配。 |
| 令牌交换成功但 Claude API 请求返回 403 | 铸造令牌的作用域未授予对该端点的访问权限。 | 根据 [OAuth 作用域](#oauth-作用域)检查规则的 `oauth_scope`。 |
| 认证失败，凭据为空 | 导出了凭据环境变量但设置为空字符串。空值仍然胜出其优先级位置。 | 使用 `unset VAR` 取消设置变量，而非 `VAR=""`。 |

## 排查交换失败

`400 invalid_grant` 响应有意不透明；具体原因仅在服务器端记录。

<Tip>
从 Claude Console 中的[认证历史页面](https://platform.claude.com/settings/workload-identity-federation?tab=history)开始。最近的交换尝试会显示评估的发行方和规则、检查的 JWT 声明以及哪个验证步骤失败，这通常可以跳过以下检查。
</Tip>

如果您仍需要从 JWT 本身进行调试，请按顺序执行以下检查：

<Steps>
  <Step title="解码 JWT">
    解码您发送的断言，以便将每个声明与您的发行方和规则配置进行比较：

    ```bash cURL nocheck
    jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson' <<< "$JWT"
    ```
  </Step>

  <Step title="检查 iss 是否匹配发行方">
    解码后的 `iss` 声明必须与注册的 `issuer_url` 逐字节相等，包括协议、端口和任何尾部斜杠。单个字符的不匹配会导致验证失败。
  </Step>

  <Step title="检查 aud 是否匹配规则">
    解码后的 `aud` 声明必须包含规则的 `audience` 值的精确匹配。当 `aud` 是数组时，一个元素必须精确匹配。
  </Step>

  <Step title="检查 sub 和每个 claims 条目">
    将 `sub` 与规则的 `subject_prefix` 进行比较（区分大小写；尾部 `*` 是前缀匹配，其他为精确匹配）。将规则 `claims` 映射中的每个键与同名的顶层声明进行比较。
  </Step>

  <Step title="检查 exp、nbf 和 iat">
    `exp` 必须在未来，`nbf`/`iat` 必须在过去，在 30 秒偏差窗口内。如果工作负载主机的时钟漂移，原本有效的令牌会被拒绝。
  </Step>

  <Step title="检查 JWKS 可达性">
    对于 `discovery` 模式，在公共 HTTPS 端口 443 上获取 `<jwks.discovery_base or issuer_url>/.well-known/openid-configuration` 并确认 `jwks_uri` 可解析。对于 `explicit_url`，直接获取 JWKS URL。对于 `inline`，确认发行方的签名密钥在您注册密钥后未轮换。

    如果发行方轮换了签名密钥并立即开始使用它签名，交换可能会在 Anthropic 的 JWKS 缓存刷新期间失败长达一分钟。参见[密钥轮换和缓存](#密钥轮换和缓存)。
  </Step>
</Steps>

## JWKS 来源模式

当您注册联合发行方时，`jwks` 字段控制 Anthropic 如何获取用于验证该发行方 JWT 签名的公钥。它是一个基于 `type` 的可区分联合：

| `jwks.type` | `jwks` 格式 | 行为 | 适用场景 |
| :--- | :--- | :--- | :--- |
| `discovery`（默认） | `{ "type": "discovery", "discovery_base": "https://..." }`（`discovery_base` 可选；当 discovery URL 与 `issuer_url` 不同时设置） | Anthropic 获取 `<discovery_base or issuer_url>/.well-known/openid-configuration`，从 discovery 文档中读取 `jwks_uri`，然后从该处获取 JWKS。 | 您的 IdP 在公共互联网上提供标准 OIDC discovery 文档。大多数托管提供商（EKS、GKE、Cloud Run、GitHub Actions、Entra ID）支持此模式。 |
| `explicit_url` | `{ "type": "explicit_url", "url": "https://..." }` | Anthropic 直接从 `url` 获取 JWKS。`issuer_url` 仅用于与 JWT `iss` 声明进行字符串比较，永远不会被拨号。 | 您的 IdP 不提供 discovery 文档，或 discovery 仅内部可用但 JWKS 可公开访问。 |
| `inline` | `{ "type": "inline", "keys": [...] }` | 您内联提供 JWK 对象数组（JWKS 文档中的 `keys` 数组，而非包装对象）。Anthropic 不发出任何出站请求。`issuer_url` 仅用于 `iss` 比较。 | 气隙环境、具有集群内部发行方 URL 的自管理 Kubernetes 集群，或您希望显式控制密钥轮换时。 |

可区分联合使伴随字段在构造上互斥。`discovery` 和 `explicit_url` 还接受可选的 `ca_cert_pem` 字符串，适用于使用私有 CA 提供 TLS 的发行方。

### 密钥轮换和缓存

在 `discovery` 和 `explicit_url` 模式下，Anthropic 缓存获取的 JWKS。如果您的身份提供商发布新的签名密钥并立即开始使用它签名令牌，出示这些令牌的交换可能会在缓存刷新期间失败长达一分钟，出现签名错误。

为避免此窗口，请在您的身份提供商开始使用新密钥签名令牌之前至少 15 分钟在 JWKS 中发布新的签名密钥，并保留被取代的密钥直到其签名的令牌过期。托管身份提供商通常自行遵循此规范。如果您运营自己的发行方（自管理的 Kubernetes 集群、SPIRE OIDC discovery 提供商或配置了轮换周期的 Okta 自定义授权服务器），请确认您的轮换策略在首次使用前发布新密钥。

<Warning>
在 `inline` 模式下没有自动密钥刷新。当您的身份提供商轮换签名密钥时，您必须使用新的 JWKS 更新发行方配置，否则所有令牌交换将无法通过签名验证。
</Warning>
