Admin API 让您能够以编程方式创建和管理 Workload Identity Federation 资源:服务账户、联合颁发者和联合规则。您可以使用它将联合配置保存在基础设施即代码中、从 CI 进行预配,并在多个组织之间复现配置,而无需在 Claude Console 中逐项点击操作。这些端点与 Admin API 的其余部分共享 /v1/organizations 路径前缀。
前提条件
本页上的每个请求都使用携带 org:admin 范围的 OAuth bearer 令牌进行身份验证。该范围仅授予具有管理员、所有者或主要所有者角色的组织成员,并授予对整个组织的访问权限:任何工作区绑定都会被忽略。获取令牌有两种方式,它们具有不同的权限:通过您自己登录获得的令牌以用户身份执行操作,而联合令牌以服务账户身份执行操作,无法执行本页上的所有操作。
交互式(您的终端)
使用 ant CLI 在专用配置文件下登录,并请求 org:admin 范围(请参阅管理员访问),然后导出 bearer 令牌。使用 --profile admin 登录会将 org:admin 凭据存储在其自己的配置文件名下,同时将其设为 CLI 的活动配置文件,并且导出的变量会应用于该 shell 中的每个 SDK 和 CLI 调用;因此请使用专门用于管理工作的 shell,完成后取消设置该变量,并使用 ant profile activate default 将 CLI 切换回来:
CLI
ant auth login --profile admin --scope "org:admin"
export ANTHROPIC_AUTH_TOKEN=$(ant auth print-credentials --profile admin --access-token)
交互式令牌的有效期很短;如果请求开始返回 401,请重新运行导出命令(它会自动刷新令牌)。
SDK 和 ant CLI 会自动读取 ANTHROPIC_AUTH_TOKEN;请在同一 shell 中保持 ANTHROPIC_API_KEY 未设置,因为这些端点会拒绝 API 密钥,而当两者都设置时,每个客户端都会使用该密钥。
工作负载(CI 和自动化)
创建一个 oauth_scope: org:admin 的联合规则,其目标是 organization_role 为 admin 的服务账户。该规则本身必须在 Claude Console 中创建:授予工作负载组织管理员访问权限是一项需要人为审慎执行的操作,而不是自动化可以自行引导完成的事情。下一节将逐步介绍这一每个组织只需执行一次的设置。
引导工作负载以管理 WIF
只需一条在 Console 中创建的规则,即可将其余联合配置纳入基础设施即代码管理:为单个受信任的工作负载授予 org:admin 范围,然后让该工作负载通过此 API 管理联合颁发者以及所有工作区范围的联合规则。
-
在 Console 中创建 org:admin 规则
在 Claude Console 中,前往 Workload identity 页面(
platform.claude.com/settings/workload-identity-federation),然后选择 Connect workload,为您的自动化工作负载创建一条联合规则,例如基础设施仓库中的 GitHub Actions 工作流。在 Advanced rule options 下,将规则的 OAuth 范围设置为org:admin:向导随后会创建具有 Admin 组织角色的新服务账户(或要求您选择一个现有的管理员服务账户作为目标)。警告
请将规则匹配到一个确切的工作负载身份,而不是宽泛的模式。除非
subject_prefix以*结尾,否则它是精确匹配。对于 GitHub Actions,请将 subject 固定到受保护的分支,例如repo:my-org/my-repo:ref:refs/heads/main。诸如repo:my-org/my-repo:*之类的尾随通配符也会匹配pull_request运行,包括从 fork 触发的运行,因此任何能够向该仓库提交拉取请求的人都可以生成org:admin令牌。请参阅限制哪些工作流可以进行身份验证。 -
交换工作负载的身份令牌
使用某个 SDK 或
antCLI 的工作负载不需要自行执行交换。通过联合环境变量将客户端指向该规则,并在不带参数的情况下构造客户端,与构造 SDK 客户端中用于推理的方式完全相同;客户端会在第一次请求时交换身份令牌,并在生成的访问令牌过期之前重新读取身份令牌并再次交换:export ANTHROPIC_FEDERATION_RULE_ID=fdrl_... # the org:admin rule from step 1 export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000 export ANTHROPIC_SERVICE_ACCOUNT_ID=svac_... # the rule's target service account export ANTHROPIC_IDENTITY_TOKEN_FILE=/path/to/jwt # or ANTHROPIC_IDENTITY_TOKEN # 仅当该规则对所有工作区或多个工作区启用时,才需要 ANTHROPIC_WORKSPACE_ID; # org:admin 端点会忽略该绑定。 unset ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN # both take precedence over federationantCLI 读取相同的变量,或接受--federation-rule、--organization-id、--service-account-id和--identity-token-file标志。对于运行多个ant命令的工作负载,请使用联合配置文件,而不是标志或环境变量:使用标志或变量时,CLI 会在每个进程中再次交换身份令牌,而携带jti声明的身份令牌(GitHub Actions 令牌就携带该声明)只会被接受一次,因此第二个命令会被拒绝;当规则对所有工作区或多个工作区启用时,配置文件也是为 CLI 的交换提供workspace_id的唯一方式,因为与 SDK 不同,CLI 不会将ANTHROPIC_WORKSPACE_ID或--workspace-id传入交换。每个 SDK 也接受相同的设置作为显式构造函数参数,各语言的示例见构造 SDK 客户端。有关完整列表和优先顺序,请参阅环境变量和凭据优先级。使用 curl 调用 API 的工作负载需要自行将 JWT 交换为短期有效的
org:adminbearer 令牌,所用的令牌交换与任何其他联合工作负载相同,并在authorization: Bearer标头中发送该令牌。 -
通过 API 管理颁发者和工作区范围的规则
配置好客户端后(或者对于 curl,将生成的令牌放入
ANTHROPIC_AUTH_TOKEN后),工作负载即可使用本页上的端点创建和管理您的联合配置。
有关工作负载生成的令牌可以执行和不能执行的操作,请参阅权限和约束。如果您已经使用 Connect workload 向导创建了颁发者、服务账户或规则,请使用以下端点列出它们,并将其导入您的基础设施即代码状态中,而不是重新创建。
身份验证
所有端点都位于 https://api.anthropic.com/v1/organizations/ 下。对联合和服务账户端点的每个请求都需要 API 版本标头和 bearer 令牌:
在 SDK 中,这些端点是 client.organization.service_accounts (typescript: client.organization.serviceAccounts; csharp, go: client.Organization.ServiceAccounts; java: client.organization().serviceAccounts(); php: $client->organization->serviceAccounts)、client.organization.federation.issuers (csharp, go: client.Organization.Federation.Issuers; java: client.organization().federation().issuers(); php: $client->organization->federation->issuers) 和 client.organization.federation.rules (csharp, go: client.Organization.Federation.Rules; java: client.organization().federation().rules(); php: $client->organization->federation->rules)(在 CLI 中为 ant organization:service-accounts、federation:issuers 和 federation:rules)。SDK 和 CLI 示例构造默认客户端,该客户端会发送来自 ANTHROPIC_AUTH_TOKEN 的 bearer 令牌,或者在自动化工作负载中,按照引导工作负载以管理 WIF 中的描述自行执行联合交换。SDK 的列表方法会按需获取后续页面,因此 limit 设置的是页面大小;PHP 和 Ruby 示例只读取一页。
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/service_accounts" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:service-accounts list
Python
client = anthropic.Anthropic()
service_accounts = client.organization.service_accounts.list()
for service_account in service_accounts:
print(f"{service_account.id}: {service_account.name}")
TypeScript
const client = new Anthropic();
for await (const serviceAccount of client.organization.serviceAccounts.list()) {
console.log(`${serviceAccount.id}: ${serviceAccount.name}`);
}
C#
AnthropicClient client = new();
var page = await client.Organization.ServiceAccounts.List();
await foreach (var serviceAccount in page.Paginate())
{
Console.WriteLine($"{serviceAccount.ID}: {serviceAccount.Name}");
}
Go
client := anthropic.NewClient()
serviceAccounts := client.Organization.ServiceAccounts.ListAutoPaging(context.Background(), anthropic.OrganizationServiceAccountListParams{})
for serviceAccounts.Next() {
serviceAccount := serviceAccounts.Current()
fmt.Printf("%s: %s\n", serviceAccount.ID, serviceAccount.Name)
}
if err := serviceAccounts.Err(); err != nil {
log.Fatal(err)
}
Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var serviceAccounts = client.organization().serviceAccounts().list();
for (var serviceAccount : serviceAccounts.autoPager()) {
IO.println(serviceAccount.id() + ": " + serviceAccount.name());
}
PHP
$client = new Client();
$serviceAccounts = $client->organization->serviceAccounts->list();
foreach ($serviceAccounts->getItems() as $serviceAccount) {
echo "{$serviceAccount->id}: {$serviceAccount->name}\n";
}
Ruby
client = Anthropic::Client.new
service_accounts = client.organization.service_accounts.list
service_accounts.data.each do |service_account|
puts "#{service_account.id}: #{service_account.name}"
end
这些端点不接受 Admin API 密钥;Admin API 页面中的 x-api-key 示例不适用于此处。
服务账户
服务账户(svac_...)是联合令牌所代表的非人类身份。请将 organization_role 设置为 developer。
创建服务账户:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/service_accounts" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"name": "inference-worker",
"organization_role": "developer"
}'
CLI
ant organization:service-accounts create \
--name inference-worker \
--organization-role developer
Python
client = anthropic.Anthropic()
service_account = client.organization.service_accounts.create(
name="inference-worker", organization_role="developer"
)
print(f"id: {service_account.id}")
print(f"name: {service_account.name}")
TypeScript
const client = new Anthropic();
const serviceAccount = await client.organization.serviceAccounts.create({
name: "inference-worker",
organization_role: "developer"
});
console.log(`id: ${serviceAccount.id}`);
console.log(`name: ${serviceAccount.name}`);
C#
using Anthropic.Models.Organization.ServiceAccounts;
AnthropicClient client = new();
var serviceAccount = await client.Organization.ServiceAccounts.Create(new()
{
Name = "inference-worker",
OrganizationRole = OrganizationRole.Developer
});
Console.WriteLine($"id: {serviceAccount.ID}");
Console.WriteLine($"name: {serviceAccount.Name}");
Go
client := anthropic.NewClient()
serviceAccount, err := client.Organization.ServiceAccounts.New(context.Background(), anthropic.OrganizationServiceAccountNewParams{
Name: "inference-worker",
OrganizationRole: anthropic.OrganizationServiceAccountNewParamsOrganizationRoleDeveloper,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", serviceAccount.ID)
fmt.Printf("name: %s\n", serviceAccount.Name)
Java
import com.anthropic.models.organization.serviceaccounts.ServiceAccountCreateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = ServiceAccountCreateParams.builder()
.name("inference-worker")
.organizationRole(ServiceAccountCreateParams.OrganizationRole.DEVELOPER)
.build();
var serviceAccount = client.organization().serviceAccounts().create(params);
IO.println("id: " + serviceAccount.id());
IO.println("name: " + serviceAccount.name());
}
PHP
use Anthropic\Organization\ServiceAccounts\ServiceAccountCreateParams\OrganizationRole;
// ...
$client = new Client();
$serviceAccount = $client->organization->serviceAccounts->create(
name: 'inference-worker',
organizationRole: OrganizationRole::DEVELOPER,
);
echo "id: {$serviceAccount->id}\n";
echo "name: {$serviceAccount->name}\n";
Ruby
client = Anthropic::Client.new
service_account = client.organization.service_accounts.create(
name: "inference-worker",
organization_role: :developer
)
puts "id: #{service_account.id}"
puts "name: #{service_account.name}"
列出服务账户:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/service_accounts?limit=20" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:service-accounts list --limit 20
Python
client = anthropic.Anthropic()
service_accounts = client.organization.service_accounts.list(limit=20)
for service_account in service_accounts:
print(f"{service_account.id}: {service_account.name}")
TypeScript
const client = new Anthropic();
for await (const serviceAccount of client.organization.serviceAccounts.list({
limit: 20
})) {
console.log(`${serviceAccount.id}: ${serviceAccount.name}`);
}
C#
AnthropicClient client = new();
var page = await client.Organization.ServiceAccounts.List(new() { Limit = 20 });
await foreach (var serviceAccount in page.Paginate())
{
Console.WriteLine($"{serviceAccount.ID}: {serviceAccount.Name}");
}
Go
client := anthropic.NewClient()
serviceAccounts := client.Organization.ServiceAccounts.ListAutoPaging(context.Background(), anthropic.OrganizationServiceAccountListParams{
Limit: anthropic.Int(20),
})
for serviceAccounts.Next() {
serviceAccount := serviceAccounts.Current()
fmt.Printf("%s: %s\n", serviceAccount.ID, serviceAccount.Name)
}
if err := serviceAccounts.Err(); err != nil {
log.Fatal(err)
}
Java
import com.anthropic.models.organization.serviceaccounts.ServiceAccountListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = ServiceAccountListParams.builder()
.limit(20)
.build();
var serviceAccounts = client.organization().serviceAccounts().list(params);
for (var serviceAccount : serviceAccounts.autoPager()) {
IO.println(serviceAccount.id() + ": " + serviceAccount.name());
}
}
PHP
$client = new Client();
$serviceAccounts = $client->organization->serviceAccounts->list(limit: 20);
foreach ($serviceAccounts->getItems() as $serviceAccount) {
echo "{$serviceAccount->id}: {$serviceAccount->name}\n";
}
Ruby
client = Anthropic::Client.new
service_accounts = client.organization.service_accounts.list(limit: 20)
service_accounts.data.each do |service_account|
puts "#{service_account.id}: #{service_account.name}"
end
归档服务账户:
cURL
curl --fail-with-body -sS -X POST "https://api.anthropic.com/v1/organizations/service_accounts/svac_01ABCDEFabcdef0123456789XY/archive" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:service-accounts archive svac_01ABCDEFabcdef0123456789XY
Python
client = anthropic.Anthropic()
service_account = client.organization.service_accounts.archive(
"svac_01ABCDEFabcdef0123456789XY"
)
print(f"id: {service_account.id}")
print(f"archived_at: {service_account.archived_at}")
TypeScript
const client = new Anthropic();
const serviceAccount = await client.organization.serviceAccounts.archive(
"svac_01ABCDEFabcdef0123456789XY"
);
console.log(`id: ${serviceAccount.id}`);
console.log(`archived_at: ${serviceAccount.archived_at}`);
C#
AnthropicClient client = new();
var serviceAccount = await client.Organization.ServiceAccounts.Archive(
"svac_01ABCDEFabcdef0123456789XY"
);
Console.WriteLine($"id: {serviceAccount.ID}");
Console.WriteLine($"archived_at: {serviceAccount.ArchivedAt:O}");
Go
client := anthropic.NewClient()
serviceAccount, err := client.Organization.ServiceAccounts.Archive(
context.Background(),
"svac_01ABCDEFabcdef0123456789XY",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", serviceAccount.ID)
fmt.Printf("archived_at: %s\n", serviceAccount.ArchivedAt)
Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var serviceAccount = client.organization().serviceAccounts()
.archive("svac_01ABCDEFabcdef0123456789XY");
IO.println("id: " + serviceAccount.id());
IO.println("archived_at: " + serviceAccount.archivedAt().orElseThrow());
PHP
$client = new Client();
$serviceAccount = $client->organization->serviceAccounts->archive(
serviceAccountID: 'svac_01ABCDEFabcdef0123456789XY',
);
echo "id: {$serviceAccount->id}\n";
echo "archived_at: {$serviceAccount->archivedAt?->format(DATE_ATOM)}\n";
Ruby
client = Anthropic::Client.new
service_account_id = "svac_01ABCDEFabcdef0123456789XY"
service_account = client.organization.service_accounts.archive(service_account_id)
puts "id: #{service_account.id}"
puts "archived_at: #{service_account.archived_at}"
创建端点会返回新的服务账户:
{
"id": "svac_...",
"name": "inference-worker",
"organization_role": "developer",
"created_at": "...",
"type": "service_account",
"...": "..."
}
要读取或更新单个服务账户,请对 /v1/organizations/service_accounts/{service_account_id} 使用 GET 和 POST。服务账户必须是某个工作区的成员,联合令牌才能在该工作区中执行操作。每个服务账户都隐式属于您组织的默认工作区;要为其他工作区添加显式成员资格,请对 /v1/organizations/service_accounts/{service_account_id}/workspaces 使用 GET、POST 和 DELETE,其中 DELETE 的目标是 .../workspaces/{workspace_id}。
有关完整的参数详细信息和响应架构,请参阅服务账户 API 参考。
联合颁发者
联合颁发者(fdis_...)用于向您的组织注册 OIDC 身份提供商。jwks 字段是一个可辨识联合类型,用于控制 Anthropic 如何获取提供商的签名密钥:
jwks 值 |
使用场景 |
|---|---|
{"type": "discovery"} |
提供商在颁发者 URL 处提供 /.well-known/openid-configuration。 |
{"type": "explicit_url", "url": "..."} |
直接指向 JWKS 端点。 |
{"type": "inline", "keys": [...]} |
为无法从公共互联网访问的提供商上传密钥集。 |
注册颁发者。此示例使用 JWKS 发现注册 GitHub Actions:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/federation_issuers" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"name": "github-actions",
"issuer_url": "https://token.actions.githubusercontent.com",
"jwks": {"type": "discovery"}
}'
CLI
ant organization:federation:issuers create \
--name github-actions \
--issuer-url https://token.actions.githubusercontent.com \
--jwks '{type: discovery}'
Python
client = anthropic.Anthropic()
issuer = client.organization.federation.issuers.create(
name="github-actions",
issuer_url="https://token.actions.githubusercontent.com",
jwks={"type": "discovery"},
)
print(f"id: {issuer.id}")
print(f"name: {issuer.name}")
print(f"issuer_url: {issuer.issuer_url}")
TypeScript
const client = new Anthropic();
const issuer = await client.organization.federation.issuers.create({
name: "github-actions",
issuer_url: "https://token.actions.githubusercontent.com",
jwks: { type: "discovery" }
});
console.log(`id: ${issuer.id}`);
console.log(`name: ${issuer.name}`);
console.log(`issuer_url: ${issuer.issuer_url}`);
C#
using Anthropic.Models.Organization.Federation.Issuers;
AnthropicClient client = new();
var issuer = await client.Organization.Federation.Issuers.Create(new()
{
Name = "github-actions",
IssuerUrl = "https://token.actions.githubusercontent.com",
Jwks = new JwksDiscovery()
});
Console.WriteLine($"id: {issuer.ID}");
Console.WriteLine($"name: {issuer.Name}");
Console.WriteLine($"issuer_url: {issuer.IssuerUrl}");
Go
client := anthropic.NewClient()
issuer, err := client.Organization.Federation.Issuers.New(context.Background(), anthropic.OrganizationFederationIssuerNewParams{
Name: "github-actions",
IssuerURL: "https://token.actions.githubusercontent.com",
JWKS: anthropic.OrganizationFederationIssuerNewParamsJWKSUnion{
OfDiscovery: &anthropic.JWKSDiscoveryParam{},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", issuer.ID)
fmt.Printf("name: %s\n", issuer.Name)
fmt.Printf("issuer_url: %s\n", issuer.IssuerURL)
Java
import com.anthropic.models.organization.federation.issuers.JwksDiscovery;
import com.anthropic.models.organization.federation.issuers.IssuerCreateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = IssuerCreateParams.builder()
.name("github-actions")
.issuerUrl("https://token.actions.githubusercontent.com")
.jwks(JwksDiscovery.builder().build())
.build();
var issuer = client.organization().federation().issuers().create(params);
IO.println("id: " + issuer.id());
IO.println("name: " + issuer.name());
IO.println("issuer_url: " + issuer.issuerUrl());
}
PHP
$client = new Client();
$issuer = $client->organization->federation->issuers->create(
name: 'github-actions',
issuerURL: 'https://token.actions.githubusercontent.com',
jwks: ['type' => 'discovery'],
);
echo "id: {$issuer->id}\n";
echo "name: {$issuer->name}\n";
echo "issuer_url: {$issuer->issuerURL}\n";
Ruby
client = Anthropic::Client.new
issuer = client.organization.federation.issuers.create(
name: "github-actions",
issuer_url: "https://token.actions.githubusercontent.com",
jwks: {type: :discovery}
)
puts "id: #{issuer.id}"
puts "name: #{issuer.name}"
puts "issuer_url: #{issuer.issuer_url}"
列出颁发者:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/federation_issuers?limit=20" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:federation:issuers list --limit 20
Python
client = anthropic.Anthropic()
issuers = client.organization.federation.issuers.list(limit=20)
for issuer in issuers:
print(f"{issuer.id}: {issuer.name}")
TypeScript
const client = new Anthropic();
for await (const issuer of client.organization.federation.issuers.list({ limit: 20 })) {
console.log(`${issuer.id}: ${issuer.name}`);
}
C#
AnthropicClient client = new();
var page = await client.Organization.Federation.Issuers.List(new() { Limit = 20 });
await foreach (var issuer in page.Paginate())
{
Console.WriteLine($"{issuer.ID}: {issuer.Name}");
}
Go
client := anthropic.NewClient()
issuers := client.Organization.Federation.Issuers.ListAutoPaging(context.Background(), anthropic.OrganizationFederationIssuerListParams{
Limit: anthropic.Int(20),
})
for issuers.Next() {
issuer := issuers.Current()
fmt.Printf("%s: %s\n", issuer.ID, issuer.Name)
}
if err := issuers.Err(); err != nil {
log.Fatal(err)
}
Java
import com.anthropic.models.organization.federation.issuers.IssuerListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = IssuerListParams.builder()
.limit(20)
.build();
var issuers = client.organization().federation().issuers().list(params);
for (var issuer : issuers.autoPager()) {
IO.println(issuer.id() + ": " + issuer.name());
}
}
PHP
$client = new Client();
$issuers = $client->organization->federation->issuers->list(limit: 20);
foreach ($issuers->getItems() as $issuer) {
echo "{$issuer->id}: {$issuer->name}\n";
}
Ruby
client = Anthropic::Client.new
issuers = client.organization.federation.issuers.list(limit: 20)
issuers.data.each do |issuer|
puts "#{issuer.id}: #{issuer.name}"
end
归档颁发者:
cURL
curl --fail-with-body -sS -X POST "https://api.anthropic.com/v1/organizations/federation_issuers/fdis_01ABCDEFabcdef0123456789XY/archive" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:federation:issuers archive \
--federation-issuer-id fdis_01ABCDEFabcdef0123456789XY
Python
client = anthropic.Anthropic()
issuer = client.organization.federation.issuers.archive(
"fdis_01ABCDEFabcdef0123456789XY"
)
print(f"id: {issuer.id}")
print(f"archived_at: {issuer.archived_at}")
TypeScript
const client = new Anthropic();
const issuer = await client.organization.federation.issuers.archive(
"fdis_01ABCDEFabcdef0123456789XY"
);
console.log(`id: ${issuer.id}`);
console.log(`archived_at: ${issuer.archived_at}`);
C#
AnthropicClient client = new();
var issuer = await client.Organization.Federation.Issuers.Archive(
"fdis_01ABCDEFabcdef0123456789XY"
);
Console.WriteLine($"id: {issuer.ID}");
Console.WriteLine($"archived_at: {issuer.ArchivedAt:O}");
Go
client := anthropic.NewClient()
issuer, err := client.Organization.Federation.Issuers.Archive(
context.Background(),
"fdis_01ABCDEFabcdef0123456789XY",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", issuer.ID)
fmt.Printf("archived_at: %s\n", issuer.ArchivedAt)
Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var issuer = client.organization().federation().issuers()
.archive("fdis_01ABCDEFabcdef0123456789XY");
IO.println("id: " + issuer.id());
IO.println("archived_at: " + issuer.archivedAt().orElseThrow());
PHP
$client = new Client();
$issuer = $client->organization->federation->issuers->archive(
federationIssuerID: 'fdis_01ABCDEFabcdef0123456789XY',
);
echo "id: {$issuer->id}\n";
echo "archived_at: {$issuer->archivedAt?->format(DATE_ATOM)}\n";
Ruby
client = Anthropic::Client.new
issuer_id = "fdis_01ABCDEFabcdef0123456789XY"
issuer = client.organization.federation.issuers.archive(issuer_id)
puts "id: #{issuer.id}"
puts "archived_at: #{issuer.archived_at}"
要读取或更新单个颁发者,请对 /v1/organizations/federation_issuers/{issuer_id} 使用 GET 和 POST。如果某个颁发者支撑着 oauth_scope 不是 workspace:developer 或 workspace:inference 的规则,OAuth 调用方将无法更新该颁发者;请参阅权限和约束。
有关完整的参数详细信息和响应架构,请参阅联合颁发者 API 参考。
联合规则
联合规则(fdrl_...)将颁发者绑定到服务账户:来自该颁发者且满足规则匹配条件的 JWT 可以生成以规则目标身份执行操作的令牌。创建请求中的 workspace_id 会在创建时在该工作区中启用规则;之后可以通过 /federation_rules/{rule_id}/workspaces 子资源添加更多工作区。创建时必须提供 workspace_id 或 applies_to_all_workspaces: true 之一。
创建规则。此示例允许来自 main 分支的 GitHub Actions 部署以该服务账户身份执行操作:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/federation_rules" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"name": "gha-deploy",
"issuer_id": "fdis_01ABCDEFabcdef0123456789XY",
"match": {
"subject_prefix": "repo:my-org/my-repo:ref:refs/heads/main",
"claims": {"repository_owner": "my-org"}
},
"target": {
"type": "service_account",
"service_account_id": "svac_01ABCDEFabcdef0123456789XY"
},
"workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
"oauth_scope": "workspace:developer",
"token_lifetime_seconds": 600
}'
CLI
ant organization:federation:rules create <<'YAML'
name: gha-deploy
issuer_id: fdis_01ABCDEFabcdef0123456789XY
match:
subject_prefix: "repo:my-org/my-repo:ref:refs/heads/main"
claims:
repository_owner: my-org
target:
type: service_account
service_account_id: svac_01ABCDEFabcdef0123456789XY
workspace_id: wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ
oauth_scope: "workspace:developer"
token_lifetime_seconds: 600
YAML
Python
client = anthropic.Anthropic()
rule = client.organization.federation.rules.create(
name="gha-deploy",
issuer_id="fdis_01ABCDEFabcdef0123456789XY",
match={
"subject_prefix": "repo:my-org/my-repo:ref:refs/heads/main",
"claims": {"repository_owner": "my-org"},
},
target={
"type": "service_account",
"service_account_id": "svac_01ABCDEFabcdef0123456789XY",
},
workspace_id="wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
oauth_scope="workspace:developer",
token_lifetime_seconds=600,
)
print(f"id: {rule.id}")
print(f"name: {rule.name}")
TypeScript
const client = new Anthropic();
const rule = await client.organization.federation.rules.create({
name: "gha-deploy",
issuer_id: "fdis_01ABCDEFabcdef0123456789XY",
match: {
subject_prefix: "repo:my-org/my-repo:ref:refs/heads/main",
claims: { repository_owner: "my-org" }
},
target: {
type: "service_account",
service_account_id: "svac_01ABCDEFabcdef0123456789XY"
},
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
oauth_scope: "workspace:developer",
token_lifetime_seconds: 600
});
console.log(`id: ${rule.id}`);
console.log(`name: ${rule.name}`);
C#
AnthropicClient client = new();
var rule = await client.Organization.Federation.Rules.Create(new()
{
Name = "gha-deploy",
IssuerID = "fdis_01ABCDEFabcdef0123456789XY",
Match = new()
{
SubjectPrefix = "repo:my-org/my-repo:ref:refs/heads/main",
Claims = new Dictionary<string, string> { ["repository_owner"] = "my-org" }
},
Target = new() { ServiceAccountID = "svac_01ABCDEFabcdef0123456789XY" },
WorkspaceID = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
OAuthScope = "workspace:developer",
TokenLifetimeSeconds = 600
});
Console.WriteLine($"id: {rule.ID}");
Console.WriteLine($"name: {rule.Name}");
Go
client := anthropic.NewClient()
rule, err := client.Organization.Federation.Rules.New(context.Background(), anthropic.OrganizationFederationRuleNewParams{
Name: "gha-deploy",
IssuerID: "fdis_01ABCDEFabcdef0123456789XY",
Match: anthropic.FederationRuleMatchParam{
SubjectPrefix: anthropic.String("repo:my-org/my-repo:ref:refs/heads/main"),
Claims: map[string]string{"repository_owner": "my-org"},
},
Target: anthropic.ServiceAccountTargetParam{
ServiceAccountID: "svac_01ABCDEFabcdef0123456789XY",
},
WorkspaceID: anthropic.String("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"),
OAuthScope: "workspace:developer",
TokenLifetimeSeconds: anthropic.Int(600),
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", rule.ID)
fmt.Printf("name: %s\n", rule.Name)
Java
import com.anthropic.core.JsonValue;
import com.anthropic.models.organization.federation.rules.FederationRuleMatch;
import com.anthropic.models.organization.federation.rules.ServiceAccountTarget;
import com.anthropic.models.organization.federation.rules.RuleCreateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var match = FederationRuleMatch.builder()
.subjectPrefix("repo:my-org/my-repo:ref:refs/heads/main")
.claims(FederationRuleMatch.Claims.builder()
.putAdditionalProperty("repository_owner", JsonValue.from("my-org"))
.build())
.build();
var params = RuleCreateParams.builder()
.name("gha-deploy")
.issuerId("fdis_01ABCDEFabcdef0123456789XY")
.match(match)
.target(ServiceAccountTarget.of("svac_01ABCDEFabcdef0123456789XY"))
.workspaceId("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ")
.oauthScope("workspace:developer")
.tokenLifetimeSeconds(600)
.build();
var rule = client.organization().federation().rules().create(params);
IO.println("id: " + rule.id());
IO.println("name: " + rule.name());
}
PHP
$client = new Client();
$rule = $client->organization->federation->rules->create(
name: 'gha-deploy',
issuerID: 'fdis_01ABCDEFabcdef0123456789XY',
match: [
'subjectPrefix' => 'repo:my-org/my-repo:ref:refs/heads/main',
'claims' => ['repository_owner' => 'my-org'],
],
target: [
'type' => 'service_account',
'serviceAccountID' => 'svac_01ABCDEFabcdef0123456789XY',
],
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
oauthScope: 'workspace:developer',
tokenLifetimeSeconds: 600,
);
echo "id: {$rule->id}\n";
echo "name: {$rule->name}\n";
Ruby
client = Anthropic::Client.new
rule = client.organization.federation.rules.create(
name: "gha-deploy",
issuer_id: "fdis_01ABCDEFabcdef0123456789XY",
match: {
subject_prefix: "repo:my-org/my-repo:ref:refs/heads/main",
claims: {repository_owner: "my-org"}
},
target: {
type: :service_account,
service_account_id: "svac_01ABCDEFabcdef0123456789XY"
},
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
oauth_scope: "workspace:developer",
token_lifetime_seconds: 600
)
puts "id: #{rule.id}"
puts "name: #{rule.name}"
列出规则,可选择按颁发者筛选:
cURL
curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/federation_rules?issuer_id=fdis_01ABCDEFabcdef0123456789XY" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:federation:rules list \
--issuer-id fdis_01ABCDEFabcdef0123456789XY
Python
client = anthropic.Anthropic()
rules = client.organization.federation.rules.list(
issuer_id="fdis_01ABCDEFabcdef0123456789XY"
)
for rule in rules:
print(f"{rule.id}: {rule.name}")
TypeScript
const client = new Anthropic();
for await (const rule of client.organization.federation.rules.list({
issuer_id: "fdis_01ABCDEFabcdef0123456789XY"
})) {
console.log(`${rule.id}: ${rule.name}`);
}
C#
AnthropicClient client = new();
var page = await client.Organization.Federation.Rules.List(new()
{
IssuerID = "fdis_01ABCDEFabcdef0123456789XY"
});
await foreach (var rule in page.Paginate())
{
Console.WriteLine($"{rule.ID}: {rule.Name}");
}
Go
client := anthropic.NewClient()
rules := client.Organization.Federation.Rules.ListAutoPaging(context.Background(), anthropic.OrganizationFederationRuleListParams{
IssuerID: anthropic.String("fdis_01ABCDEFabcdef0123456789XY"),
})
for rules.Next() {
rule := rules.Current()
fmt.Printf("%s: %s\n", rule.ID, rule.Name)
}
if err := rules.Err(); err != nil {
log.Fatal(err)
}
Java
import com.anthropic.models.organization.federation.rules.RuleListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = RuleListParams.builder()
.issuerId("fdis_01ABCDEFabcdef0123456789XY")
.build();
var rules = client.organization().federation().rules().list(params);
for (var rule : rules.autoPager()) {
IO.println(rule.id() + ": " + rule.name());
}
}
PHP
$client = new Client();
$rules = $client->organization->federation->rules->list(
issuerID: 'fdis_01ABCDEFabcdef0123456789XY',
);
foreach ($rules->getItems() as $rule) {
echo "{$rule->id}: {$rule->name}\n";
}
Ruby
client = Anthropic::Client.new
rules = client.organization.federation.rules.list(
issuer_id: "fdis_01ABCDEFabcdef0123456789XY"
)
rules.data.each do |rule|
puts "#{rule.id}: #{rule.name}"
end
归档规则:
cURL
curl --fail-with-body -sS -X POST "https://api.anthropic.com/v1/organizations/federation_rules/fdrl_01ABCDEFabcdef0123456789XY/archive" \
-H "authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01"
CLI
ant organization:federation:rules archive \
--federation-rule-id fdrl_01ABCDEFabcdef0123456789XY
Python
client = anthropic.Anthropic()
rule = client.organization.federation.rules.archive("fdrl_01ABCDEFabcdef0123456789XY")
print(f"id: {rule.id}")
print(f"archived_at: {rule.archived_at}")
TypeScript
const client = new Anthropic();
const rule = await client.organization.federation.rules.archive(
"fdrl_01ABCDEFabcdef0123456789XY"
);
console.log(`id: ${rule.id}`);
console.log(`archived_at: ${rule.archived_at}`);
C#
AnthropicClient client = new();
var rule = await client.Organization.Federation.Rules.Archive(
"fdrl_01ABCDEFabcdef0123456789XY"
);
Console.WriteLine($"id: {rule.ID}");
Console.WriteLine($"archived_at: {rule.ArchivedAt:O}");
Go
client := anthropic.NewClient()
rule, err := client.Organization.Federation.Rules.Archive(
context.Background(),
"fdrl_01ABCDEFabcdef0123456789XY",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", rule.ID)
fmt.Printf("archived_at: %s\n", rule.ArchivedAt)
Java
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var rule = client.organization().federation().rules()
.archive("fdrl_01ABCDEFabcdef0123456789XY");
IO.println("id: " + rule.id());
IO.println("archived_at: " + rule.archivedAt().orElseThrow());
PHP
$client = new Client();
$rule = $client->organization->federation->rules->archive(
federationRuleID: 'fdrl_01ABCDEFabcdef0123456789XY',
);
echo "id: {$rule->id}\n";
echo "archived_at: {$rule->archivedAt?->format(DATE_ATOM)}\n";
Ruby
client = Anthropic::Client.new
rule_id = "fdrl_01ABCDEFabcdef0123456789XY"
rule = client.organization.federation.rules.archive(rule_id)
puts "id: #{rule.id}"
puts "archived_at: #{rule.archived_at}"
列表端点会返回一页规则以及下一页的游标:
{
"data": [{ "id": "fdrl_...", "name": "gha-deploy", "...": "..." }],
"next_page": "..."
}
要读取或更新单个规则,请对 /v1/organizations/federation_rules/{rule_id} 使用 GET 和 POST。要管理规则可以在其中生成令牌的工作区,请对 /v1/organizations/federation_rules/{rule_id}/workspaces 使用 GET 和 POST,并对 /v1/organizations/federation_rules/{rule_id}/workspaces/{workspace_id} 使用 DELETE。
有关完整的参数详细信息和响应架构,请参阅联合规则 API 参考。
权限和约束
注意
- 通过 OAuth 身份验证的调用方只能创建或修改
oauth_scope为workspace:developer或workspace:inference的规则。要创建或修改具有任何其他范围(例如org:admin或workspace:manage_tunnels)的规则,请使用 Console。- 如果某个联合颁发者支撑着
oauth_scope不是workspace:developer或workspace:inference(例如org:admin或workspace:manage_tunnels)的规则,OAuth 调用方将无法更新该颁发者。建议为引导规则注册一个专用颁发者,以便工作区范围规则背后的颁发者仍可通过 API 更新。- 这些端点不接受 Admin API 密钥,无论是读取还是写入;请使用
org:adminOAuth 令牌。
oauth_scope: org:admin 的规则必须以 organization_role 为 admin 的服务账户为目标。资源名称必须匹配 ^[a-z0-9-]+$,长度为 1 到 255 个字符,并且对于每种资源类型在组织内必须唯一;有关完整的字段级约束,请参阅验证规则。
分页和归档
服务账户、联合颁发者和联合规则的列表端点接受 limit(1 到 100,默认为 20)以及取自上一个响应的 page 游标。在下一个请求中,将响应的 next_page 值作为 page 查询参数传递。规则工作区子资源列表会返回完整集合,不进行分页。已归档的资源默认不会出现在列表中;传递 include_archived=true 可将其包含在内。
归档是一种软删除,并且是幂等的:归档已归档的资源会成功。当仍有有效的联合规则引用某个颁发者或服务账户时,归档该颁发者或服务账户会返回 400;请先归档该规则。
另请参阅
- Workload Identity Federation:概念以及 Console 设置演练
- WIF 参考:环境变量、验证规则、OAuth 范围和错误代码
- Admin API:组织管理功能的其余部分
- Admin API 参考:服务账户和联合端点的生成式请求和响应架构