---
title: Anthropic | Keycard
description: Set up credential brokering for Anthropic APIs so your workloads authenticate with Keycard-issued OIDC tokens instead of static API keys
---

Your application authenticates to Keycard with [workload identity](/concepts/providers/#workload-identity/index.md) and exchanges its token for a Keycard-issued OIDC JWT scoped to Anthropic. The Anthropic SDK uses that JWT to perform [Workload Identity Federation (WIF)](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation) and get a short-lived access token. No static API keys anywhere in the chain.

Your AppUses credential with Anthropic

Keycard-minted access token

Claude APIShort-lived token, no API keys

Keycard ZoneIssues OIDC JWT for Anthropic

Anthropic WIFValidates JWT, returns access token

Note

This guide covers **credential brokering**. Your application calls the Anthropic API with dynamically issued tokens. For authenticating *users* into your zone, see [Identity Providers](/admin/identity-providers/index.md).

## Prerequisites

- A [Keycard zone](/concepts/zones/index.md)
- An admin role in your Anthropic organization with permission to manage [Workload Identity Federation](https://platform.claude.com/settings/workload-identity-federation) (Organization Owner or Organization Admin)
  - **Organization ID** (UUID) — found in small print on [Settings → Organization](https://platform.claude.com/settings/organization)

## Keycard setup

KEYCARD

Create an application, resource, and link them together.

1. **Create the Anthropic resource**

   In [Keycard Console](https://console.keycard.ai), go to your zone and navigate to **Resources**.

   - Click **Add Resource**
   - Set the **Resource Identifier** to `https://api.anthropic.com`
   - Select your **Zone Provider** as the credentials provider — this tells Keycard to issue OIDC tokens signed by the zone itself rather than brokering through an external OAuth flow
   - Under **Advanced Settings**, set the **Credential Lifetime** to `1h`

2. **Create an application and link the resource**

   Navigate to **Applications**.

   - Click **Add Application**
   - Give it a name (e.g. `anthropic-workload`)
   - Note the **Application ID** — not yet shown in the UI; open the application and copy the ID from the browser URL bar

   Then open the application and go to **Dependencies**.

   - Click **Add Dependency**
   - Select the `https://api.anthropic.com` resource

   This authorizes the application to request tokens scoped to the Anthropic API.

3. **Create application credentials (local development)**

   For local development with `keycard run`, you need a client ID and secret. In production, applications authenticate with [workload identity](/concepts/providers/#workload-identity/index.md) instead.

   Open your application and go to **Application Credentials**.

   - Click **Add Credential** → **Client ID & Secret**
   - Note the **Client ID** and **Client Secret** — the secret is only shown once

4. **Note the zone’s OIDC issuer URL**

   Find your zone URL on the zone settings page in [Keycard Console](https://console.keycard.ai). Anthropic needs this as the issuer URL when you register the federation rule in the next section.

   Your zone serves standard OIDC discovery at `https://<zone-id>.keycard.cloud/.well-known/openid-configuration` — Anthropic fetches this automatically to discover the JWKS and verify token signatures.

## Anthropic setup

ANTHROPIC

Register Keycard as a trusted issuer and create a federation rule for your workload.

1. **Create a service account**

   In the [Anthropic Platform Console](https://platform.claude.com/settings/service-accounts), go to **Settings → Service accounts → Create service account**.

   Give it a name (e.g. `keycard-workload`). Note the service account ID (`svac_...`).

2. **Create a workspace and link the service account**

   The Default Workspace has no ID and can’t be used with WIF. Create a dedicated workspace for your Keycard workloads.

   Go to **Settings → [Workspaces](https://platform.claude.com/settings/workspaces) → Create workspace**. Give it a name (e.g. `keycard-workloads`).

   Note the workspace ID (`wrkspc_...`) from the workspaces list. You’ll need it in the code examples below.

   Once created, select the workspace from the dropdown in the top navigation, then go to **Manage → Service accounts → Add service account** and add the service account from step 1. This links it to the workspace and determines which models and rate limits it can use.

3. **Register Keycard as an issuer**

   In the org-level [Workload Identity Federation](https://platform.claude.com/settings/workload-identity-federation) settings, on the **Issuers** tab, click **Create issuer**.

   | Field       | Value                                                                                            |
   | ----------- | ------------------------------------------------------------------------------------------------ |
   | Name        | A label, e.g. `keycard-prod`                                                                     |
   | Issuer URL  | `https://<zone-id>.keycard.cloud` — must match the `iss` claim in the Keycard-issued JWT exactly |
   | JWKS source | `discovery` — Keycard zones serve `.well-known/openid-configuration` publicly                    |

4. **Create a federation rule**

   On the **Rules** tab, click **New Rule**.

   | Section                | Value                                                                                                                                                                 |
   | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | Issuer                 | Select the `keycard-prod` issuer from step 3                                                                                                                          |
   | Match → Subject prefix | The **Application ID** from Keycard (the `sub` claim in the OIDC token)                                                                                               |
   | Target                 | The service account from step 1                                                                                                                                       |
   | Workspaces             | Select the workspaces this rule can mint tokens for. The service account from step 1 must be a member of each selected workspace, otherwise token exchanges will fail |
   | Scope                  | `workspace:developer` (default — grants the same access as an API key)                                                                                                |
   | Token lifetime         | `3600` seconds (default) — adjust based on your security requirements                                                                                                 |

   Note the rule ID (`fdrl_...`). Your workload passes this in every token exchange request.

   Note

   The workspace you select here must match the workspace you linked the service account to in step 2. If the service account isn’t a member of the workspace, the federation rule will be created but token exchanges will return an error.

## Use from code

USE FROM CODE

Get a Keycard OIDC token and pass it to the Anthropic SDK for automatic WIF exchange.

Your application does two things at runtime:

1. Gets a Keycard OIDC token scoped to `https://api.anthropic.com` via `client_credentials` with a `resource` parameter
2. Passes that token to the Anthropic SDK, which handles the WIF exchange and refresh automatically

Note

The Python and Go Keycard SDKs support `client_credentials` with a `resource` parameter natively. The TypeScript SDK doesn’t yet — that example hits the token endpoint directly. SDK support is coming for all languages.

- [Python](#tab-panel-152)
- [TypeScript](#tab-panel-153)
- [Go](#tab-panel-154)
- [cURL](#tab-panel-155)

```
from keycardai.oauth import Client, BasicAuth
from 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)
}
```

Terminal window

```
# 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

VERIFY

Confirm the federation chain works end-to-end.

**In Keycard Console** — open **Audit Log**. You should see:

|                     |                                                   |
| ------------------- | ------------------------------------------------- |
| `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 attempt with your zone’s issuer URL and the matched federation rule.

## Related

RELATED

- [Providers (concepts)](/concepts/providers/index.md) — the trust model behind identity and access federation
- [Access policies](/admin/access-policies/index.md) — control which applications can access the Anthropic resource
- [Run apps without static secrets](/guides/run-apps-without-static-secrets/index.md) — deploy with workload identity on Fly.io
- [Anthropic WIF documentation](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation) — Anthropic’s setup reference
