Configure Anthropic
Set up credential brokering so workloads authenticate to Claude API with Keycard-issued tokens instead of static API keys
Configure Workload Identity Federation (WIF) between Keycard and Anthropic. Your applications get Keycard OIDC tokens that Anthropic exchanges for short-lived API credentials — no static API keys anywhere.
Prerequisites
Section titled “Prerequisites”Before starting:
- A Keycard zone
- Anthropic Organization Owner or Admin role with access to Workload Identity Federation settings
- Your Anthropic Organization ID (UUID) from Settings → Organization
Configure Keycard
Section titled “Configure Keycard”-
Create the Anthropic resource
In Keycard Console, navigate to Resources → Add Resource.
Field Value Resource Identifier https://api.anthropic.comCredentials Provider Your zone provider Credential Lifetime 1h(under Advanced Settings) -
Create an application
Navigate to Applications → Add Application.
Field Value Name e.g. anthropic-workloadNote the Application ID from the browser URL bar after creating.
-
Link the resource
Open the application → Dependencies → Add Dependency → select
https://api.anthropic.com. -
Create application credentials (local development only)
Open the application → Application Credentials → Add Credential → Client ID & Secret.
Note the Client ID and Client Secret — the secret is shown once.
-
Note the zone issuer URL
Find your zone URL on the zone settings page. Anthropic needs this as the issuer URL:
https://<zone-id>.keycard.cloud
Configure Anthropic
Section titled “Configure Anthropic”-
Create a service account
In Anthropic Platform Console, go to Settings → Service accounts → Create service account.
Field Value Name e.g. keycard-workloadNote the service account ID (
svac_...). -
Create a workspace
The Default Workspace has no ID and can’t be used with WIF.
Go to Settings → Workspaces → Create workspace.
Field Value Name e.g. keycard-workloadsNote the workspace ID (
wrkspc_...) from the workspaces list. -
Link the service account to the workspace
Select the workspace from the top navigation dropdown → Manage → Service accounts → Add service account → select the service account from step 1.
-
Register Keycard as an issuer
In Workload Identity Federation settings, on the Issuers tab → Create issuer.
Field Value Name e.g. keycard-prodIssuer URL https://<zone-id>.keycard.cloudJWKS source discovery -
Create a federation rule
On the Rules tab → New Rule.
Field Value Issuer Select your Keycard issuer Match → Subject prefix Your Keycard Application ID Target Your service account Workspaces Select the workspace from step 2 Scope workspace:developerToken lifetime 3600secondsNote the rule ID (
fdrl_...).
Use from code
Section titled “Use from code”Get a Keycard OIDC token and pass it to the Anthropic SDK for automatic WIF exchange.
from keycardai.oauth import Client, BasicAuthfrom anthropic import Anthropic, WorkloadIdentityCredentials
# 1. Get a Keycard OIDC token scoped to Anthropic.with Client( "https://<zone-id>.keycard.cloud", auth=BasicAuth("<your-client-id>", "<your-client-secret>"),) as kc: token = kc.exchange_token( grant_type="client_credentials", resource="https://api.anthropic.com", )
# 2. Use it with the Anthropic SDK — WIF exchange happens automatically.client = Anthropic( credentials=WorkloadIdentityCredentials( identity_token_provider=lambda: token.access_token, federation_rule_id="<fdrl_...>", organization_id="<anthropic-org-id>", service_account_id="<svac_...>", workspace_id="<wrkspc_...>", ),)
message = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, messages=[{"role": "user", "content": "Hello from a Keycard workload"}],)print(message.content[0].text)import Anthropic from "@anthropic-ai/sdk";import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";
/** Get a resource-scoped JWT via client_credentials grant. */async function keycardClientCredentials( tokenUrl: string, clientId: string, clientSecret: string, resource: string,): Promise<string> { const resp = await fetch(tokenUrl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`, }, body: new URLSearchParams({ grant_type: "client_credentials", resource }), }); if (!resp.ok) throw new Error(`client_credentials failed: ${await resp.text()}`); const data = (await resp.json()) as { access_token: string }; return data.access_token;}
// 1. Get a Keycard OIDC token scoped to Anthropic.const tokenUrl = "https://<zone-id>.keycard.cloud/oauth/2/token";const keycardJwt = await keycardClientCredentials( tokenUrl, "<your-client-id>", "<your-client-secret>", "https://api.anthropic.com",);
// 2. Use it with the Anthropic SDK — WIF exchange happens automatically.const client = new Anthropic({ credentials: oidcFederationProvider({ identityTokenProvider: () => keycardJwt, federationRuleId: "<fdrl_...>", organizationId: "<anthropic-org-id>", serviceAccountId: "<svac_...>", workspaceId: "<wrkspc_...>", baseURL: "https://api.anthropic.com", fetch, }),});
const message = await client.messages.create({ model: "claude-sonnet-4-6", max_tokens: 1024, messages: [{ role: "user", content: "Hello from a Keycard workload" }],});console.log(message.content[0].text);package main
import ( "context" "fmt" "log"
"github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/option" "github.com/keycardai/credentials-go/oauth")
func main() { ctx := context.Background()
// 1. Get a Keycard OIDC token scoped to Anthropic. kc := oauth.NewClientCredentialsClient( "https://<zone-id>.keycard.cloud", oauth.WithCCBasicAuth("<your-client-id>", "<your-client-secret>"), )
keycardToken, err := kc.RequestToken(ctx, oauth.ClientCredentialsRequest{ Resource: "https://api.anthropic.com", }) if err != nil { log.Fatal(err) }
// 2. Use it with the Anthropic SDK — WIF exchange happens automatically. client := anthropic.NewClient( option.WithFederationTokenProvider( func(_ context.Context) (string, error) { return keycardToken.AccessToken, nil }, option.FederationOptions{ FederationRuleID: "<fdrl_...>", OrganizationID: "<anthropic-org-id>", ServiceAccountID: "<svac_...>", WorkspaceID: "<wrkspc_...>", }, ), )
message, err := client.Messages.New(ctx, anthropic.MessageNewParams{ Model: "claude-sonnet-4-6", MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from a Keycard workload")), }, }) if err != nil { log.Fatal(err) } fmt.Println(message.Content[0].Text)}# 1. Get a Keycard OIDC token scoped to Anthropic.KC_TOKEN=$(curl -sS "https://<zone-id>.keycard.cloud/oauth/2/token" \ -u "<your-client-id>:<your-client-secret>" \ -d "grant_type=client_credentials" \ -d "resource=https://api.anthropic.com" \ | jq -r .access_token)
# 2. Exchange the Keycard token at Anthropic's WIF endpoint.ANTHROPIC_TOKEN=$(curl -sS https://api.anthropic.com/v1/oauth/token \ -H "content-type: application/json" \ -d "{ \"grant_type\": \"urn:ietf:params:oauth:grant-type:jwt-bearer\", \"assertion\": \"${KC_TOKEN}\", \"federation_rule_id\": \"<fdrl_...>\", \"organization_id\": \"<anthropic-org-id>\", \"service_account_id\": \"<svac_...>\", \"workspace_id\": \"<wrkspc_...>\" }" | jq -r .access_token)
# 3. Call the API.curl -sS https://api.anthropic.com/v1/messages \ -H "authorization: Bearer ${ANTHROPIC_TOKEN}" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello from a Keycard workload"}] }' | jq -r '.content[0].text'Verify
Section titled “Verify”In Keycard Console — open Audit Log. Look for:
| Event | Description |
|---|---|
credentials:issue | OIDC token issued for https://api.anthropic.com |
In Anthropic Platform Console — go to Settings → Workload identity → Authentication events. You should see the exchange with your zone’s issuer URL and matched federation rule.
Troubleshooting
Section titled “Troubleshooting”Token exchange returns “service account not a member of workspace” The service account must be explicitly added to the workspace. Go to the workspace → Manage → Service accounts and add it.
“Invalid issuer” error
The issuer URL in Anthropic must match the Keycard zone URL exactly, including the protocol (https://) and no trailing slash.
Federation rule doesn’t match
Check that the Subject prefix in the rule matches your Keycard Application ID. The sub claim in the Keycard-issued JWT contains this value.