Anthropic Workload Identity Federation

Let a VM call the Claude API without storing an Anthropic API key. The VM gets a short-lived exe.dev token, and Anthropic exchanges it for a short-lived access token for one of your service accounts.

This calls api.anthropic.com directly, so usage is billed to your Anthropic organization. To use exe.dev's built-in models instead, see the LLM integration.

Setup uses two browser tabs: the exe.dev Integrations page and the Claude Console's Workload identity settings.

1. Start the integration in exe.dev

On the Integrations page, add an Identity Federation integration and choose Anthropic. Enter a name, such as anthropic-wif, and choose the VMs to attach.

The dialog shows an Issuer and a Subject. You will paste both into Anthropic in the next step. Keep the dialog open; the subject is reserved for 15 minutes.

2. Create the rule in Anthropic

In the Claude Console, open Workload identity settings, select Connect workload, and choose Custom OIDC.

Anthropic field Value
Issuer URL The exe.dev Issuer. Use OIDC discovery for signing keys.
Subject match The exe.dev Subject, exactly. Do not use a wildcard.
Audience match api.anthropic.com
Workspace The workspace that receives the API usage
Service account An account in that workspace; the VM acts as it
Scope workspace:inference to call Claude only, or workspace:developer for broader access

After you save the rule, the Console shows the IDs you need in the next step.

3. Enter the IDs and save

Back in the exe.dev dialog, fill in:

Field Where it comes from
Organization ID Your Anthropic organization (a UUID)
Federation rule ID The rule you just created (fdrl_...)
Service account ID The rule's service account (svac_...)
Workspace ID Only if the rule covers more than one workspace (wrkspc_..., or default)

Click Run. If you don't have the IDs yet, you can save with the fields empty and edit the integration later to add them.

4. Call Claude from the VM

Run this on an attached VM. It reads the IDs from the integration, exchanges a fresh exe.dev token for an Anthropic access token, and sends a message:

EXE_WIF_URL=https://anthropic-wif.int.exe.xyz
META="$(curl -fsS "$EXE_WIF_URL/metadata")"
JWT="$(curl -fsS "$EXE_WIF_URL/token" | jq -er .token)"

ACCESS_TOKEN="$(
  jq -n --arg assertion "$JWT" --argjson meta "$META" '{
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    assertion: $assertion,
    federation_rule_id: $meta.fed_rule_id,
    organization_id: $meta.org_id,
    service_account_id: $meta.svc_account_id
  } + (if $meta.workspace_id then {workspace_id: $meta.workspace_id} else {} end)' |
  curl -fsS https://api.anthropic.com/v1/oauth/token \
    -H 'content-type: application/json' -d @- |
  jq -er .access_token
)"

curl -fsS https://api.anthropic.com/v1/messages \
  -H "authorization: Bearer $ACCESS_TOKEN" \
  -H 'anthropic-version: 2023-06-01' \
  -H 'content-type: application/json' \
  -d '{"model":"claude-opus-5-5","max_tokens":128,"messages":[{"role":"user","content":"Hello from exe.dev"}]}'

unset JWT ACCESS_TOKEN

Replace anthropic-wif with your integration's name. For a team integration, use https://<name>.team.exe.xyz.

Tokens

  • Fetch a new exe.dev token from /token for every exchange. Anthropic rejects a token it has already seen.
  • Get a new Anthropic access token before expires_in runs out.
  • Both tokens are credentials. Don't print, log, or commit them.

Anthropic's SDKs can do the exchange and refresh for you. See Anthropic's WIF reference.

Use the CLI instead

The CLI prints the issuer and subject only after it creates the integration, so add the IDs with a second command:

ssh exe.dev integrations add wif --name anthropic-wif \
  --audience api.anthropic.com --consumer anthropic \
  --attach vm:example-vm

Create the Anthropic rule with the printed Issuer and Subject, then:

ssh exe.dev integrations edit anthropic-wif \
  --metadata=org_id=00000000-0000-0000-0000-000000000000 \
  --metadata=fed_rule_id=fdrl_EXAMPLE \
  --metadata=svc_account_id=svac_EXAMPLE

Add --metadata=workspace_id=... if the rule covers more than one workspace, and --team to add for a team integration. edit replaces all metadata, so include every ID each time.

Troubleshooting

  • The exchange is rejected. Check that the rule's issuer, subject, and audience exactly match the integration. The Console's authentication history shows why a token was rejected.
  • /token or /metadata doesn't respond. The integration isn't attached to this VM.
  • The rule covers more than one workspace. Anthropic then requires a workspace ID in every exchange; add it to the integration.