●MODEL — Claude Fable 5 reached general availability on June 9 with a 1M-token context, always-on adaptive thinking, and 128K output●PLATFORM — The Developer Platform adds code execution, an MCP connector, a Files API, and prompt caching up to one hour●MCP — Admins can provision MCP connectors org-wide via Okta, giving users zero-touch access on first login●SANDBOX — Claude Managed Agents now run in your own sandbox and connect to private MCP servers●CODING — Opus 4.8 scores 72.5% on SWE-bench and 43.2% on Terminal-bench, excelling at long-running work●LINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per task●MODEL — Claude Fable 5 reached general availability on June 9 with a 1M-token context, always-on adaptive thinking, and 128K output●PLATFORM — The Developer Platform adds code execution, an MCP connector, a Files API, and prompt caching up to one hour●MCP — Admins can provision MCP connectors org-wide via Okta, giving users zero-touch access on first login●SANDBOX — Claude Managed Agents now run in your own sandbox and connect to private MCP servers●CODING — Opus 4.8 scores 72.5% on SWE-bench and 43.2% on Terminal-bench, excelling at long-running work●LINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per task
Drop Your Static Claude API Keys: Moving CI and Production to Keyless Auth with Workload Identity Federation
Workload Identity Federation is now generally available on the Claude Platform. This guide walks through replacing long-lived sk-ant- keys with short-lived OIDC tokens, including keyless GitHub Actions auth, the migration steps, and token refresh design.
Have you ever pushed a file containing an API key to GitHub and felt your stomach drop? It happened to me once, back when I was juggling several repositories as an indie developer, and I spent a frantic afternoon revoking and rotating. There was no real damage, but the incident taught me something at a gut level: the danger isn't carelessness, it's the structure. A long-lived secret string will inevitably end up somewhere — in history, in logs, in CI — and stay there.
In June 2026, Workload Identity Federation (WIF) became generally available on the Claude Platform. In one sentence: you stop holding a long-lived sk-ant-... key entirely and instead have a short-lived token minted at request time. Once the premise of "store the key" disappears, most of the headaches — leakage, rotation, inventory — fall away with it. Running automated publishing across several Dolice sites by myself, I found this a quiet change with an outsized payoff. Let's walk through how it works and how to land it in CI and production, including the spots where people get stuck.
The structural risk in static keys
The trouble with a static key isn't performance or price — it's the absence of an expiry. Once issued, an sk-ant-... key is valid forever unless you explicitly revoke it. From the moment that string is exposed until the instant you finish revoking, the entire window is attackable.
And exposure routes are surprisingly varied: commit history, CI log output, shell history files, container image layers, stack traces shipped to your error monitor. If even one slips through, anyone holding that string can impersonate you. Because the key itself is the credential, this is structural, not a matter of discipline. I wrote up the emergency response in how to handle a committed API key, but the strongest defense is to not hold a key at all.
From "holding a key" to "minted on demand"
WIF inverts how you hold credentials. A traditional API key is itself the credential. With WIF, a token is issued — only when needed — to a principal called a service account. You don't hold the key; the key is minted for you.
The flow has three stages:
An identity provider (IdP) you already operate issues a signed OIDC token (a JWT) to the workload. On most platforms this is ambient: a Kubernetes projected service-account token, the Google Cloud metadata server, Azure IMDS, or the GitHub Actions OIDC endpoint.
The SDK presents that JWT to Claude's token endpoint. Anthropic verifies the signature and claims, then exchanges it for a short-lived Anthropic access token.
The SDK attaches that token to every request and re-exchanges it before it expires. Your application code calls the API as usual, passing no api_key at all.
The key point is that the SDK carries the exchange-and-refresh loop for you. All you configure is "which rule, and whose JWT, to exchange."
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A concrete path from static sk-ant- keys to OIDC tokens that expire in minutes
✦A GitHub Actions setup that calls the Claude API with zero API keys in CI secrets
✦The trap where ANTHROPIC_API_KEY silently shadows federation, and how ant auth status reveals it
✦Designing token lifetime as the lesser of the rule's token_lifetime_seconds and the JWT's remaining life
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Three things to register: service account, issuer, rule
Before any workload can federate, you create three resources in the Claude Console. Together they express "a token signed by issuer X, with claims that look like Y, may act as service account Z."
A service account (svac_...) is a non-human identity inside your organization. It represents who a federated token acts as. It has no email, no password, no Console login. It becomes active only when added to a workspace's members, and the minted token follows that workspace's rate limits and usage attribution, just like an API key.
A federation issuer (fdis_...) registers an OIDC IdP with your organization — declaring "JWTs signed by this provider may assert workload identity for my org." Its core config is the Issuer URL that exactly matches the JWT's iss claim, and how Anthropic fetches the public keys to verify signatures (most IdPs work with discovery).
A federation rule (fdrl_...) bridges an issuer and a service account: "when a JWT from issuer X satisfies condition Y, mint a token for service account Z with scope S." You can narrow by subject prefix, exact audience, exact claim values, or a CEL expression for complex logic. Make this as specific as your IdP's claims allow — a rule that matches too broadly grants more than you intend.
Rules are evaluated by ID. The client states which rule to use in the exchange request, and Anthropic verifies the JWT satisfies that rule's match criteria. There is no implicit rule search.
Exchanging the JWT for a short-lived token
The exchange itself is plain OAuth. The workload presents its IdP JWT to POST /v1/oauth/token using the RFC 7523jwt-bearer grant. Anthropic verifies the signature against the registered JWKS, checks exp/nbf/iat, and matches against the rule you named. The response is a standard OAuth 2.0 token response containing a short-lived sk-ant-oat01-... token.
With the SDK you never write this exchange yourself. The recommended production pattern is to construct the client with no arguments and inject per-environment values via environment variables, so you can ship one container image everywhere.
from anthropic import Anthropic, WorkloadIdentityCredentials, IdentityTokenFile# Explicit form shown; production prefers zero-arg construction + env injectionclient = Anthropic( credentials=WorkloadIdentityCredentials( identity_token_provider=IdentityTokenFile( "/var/run/secrets/anthropic.com/token" ), federation_rule_id="fdrl_...", organization_id="00000000-0000-0000-0000-000000000000", service_account_id="svac_...", workspace_id="wrkspc_...", ),)message = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, messages=[{"role": "user", "content": "Hello, Claude"}],)print(message.content[0].text)
Notice there is no api_key anywhere. The long-lived secret is gone from both the code and the image.
Calling Claude from GitHub Actions without a key
For an indie developer, CI is where WIF pays off most visibly. I run content generation across several sites with GitHub Actions and scheduled jobs, and the static key there was a long-standing weak point. The moment a key lives in repository secrets, it can leak through workflow logs or third-party Actions.
GitHub Actions can issue OIDC tokens, so registering it as a WIF issuer lets you authenticate with no key in secrets at all. The workflow needs only the id-token: write permission and a few lines to write the OIDC token to a file and hand it to the SDK via environment variables.
Every value here is a vars entry — harmless identifiers — and not one of them is a secret. IDs like svac_... and fdrl_... carry no power on their own. Simply removing the key as an asset from CI made the mental weight of inventory much lighter. For the broader picture of wiring GitHub Actions to Claude, see GitHub Actions and Claude API automation.
The trap you will hit: the API key wins silently
This is the single most important thing in this article. Every SDK resolves credentials in the same five-tier order: constructor arguments, then ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, then an explicit ANTHROPIC_PROFILE, then the federation environment variables, then the implicit active profile. The first source that yields a credential wins.
The catch is that ANTHROPIC_API_KEY sits above the federation tiers. So if a stale key lingers anywhere in the environment, it silently shadows federation even when WIF is configured perfectly. No error, no warning. This is the hardest failure to spot: "I set it up, but it isn't being used."
Here is the no-downtime migration:
Configure federation in parallel. Leave the existing ANTHROPIC_API_KEY in place and confirm the rule matches your workload's token.
Smoke-test which credential wins. Run ant auth status inside the workload. At this stage the API key still wins, by precedence.
Unset ANTHROPIC_API_KEY everywhere it is injected — CI secrets, container env, shell profiles — then re-run ant auth status and confirm the federation source is selected.
Revoke the API key. Once the workload runs on the federated token, delete the key in the Console.
# Always confirm which tier was selected$ ant auth status# Example:# Resolved credential source: ANTHROPIC_API_KEY (env) <- key still winning# ...# Unset the key and re-check$ unset ANTHROPIC_API_KEY$ ant auth status# Resolved credential source: workload identity federation (fdrl_...) <- migrated
I personally nearly burned half a day on "I configured it but nothing changed" before I understood this precedence. Building the habit of running ant auth status first removes the trap almost entirely.
Designing token lifetime and refresh
Since these are short-lived tokens, understanding lifetime and refresh keeps production stable. The minted token's lifetime is the lesser of the rule's token_lifetime_seconds (default 3600, range 60–86400) and twice the remaining life of the IdP JWT you presented, with a 60-second floor. That second bound prevents the Anthropic token from outliving the upstream identity by more than a small margin.
The SDK handles refresh on two tiers. At expiry minus 120 seconds it attempts an advisory refresh; if the token endpoint is unreachable, the cached token is still valid for roughly 90 more seconds, so work continues. At expiry minus 30 seconds it performs a mandatory refresh, and a failure there raises an error because the cached token is too close to expiry to be safe.
Two design implications follow. First, setting token_lifetime_seconds too short increases exchange frequency; for long batch jobs, avoid extreme values while keeping the JWT's own lifetime in mind. Second, because the SDK re-reads ANTHROPIC_IDENTITY_TOKEN_FILE on every exchange, it transparently picks up rotated tokens (such as Kubernetes projected tokens) with no extra work. A long-running job that mysteriously fails auth partway through is often a symptom of missing this detail.
Where to start as a solo developer
WIF can look like heavyweight enterprise machinery, but the entry point is light. For interactive development, ant auth login lets you complete OAuth authorization in a browser and clear the key from your hands — so you stop leaving sk-ant-... in shell history and dotfiles. That alone is worth adopting.
For production and CI, I'd recommend moving one low-blast-radius workload at a time. WIF gives you a "no key held" design, but it is not a complete security story by itself: if the IdP that signs the JWT is weak, the whole chain is weak. Pair it with the conditional access and audit logging your IdP already supports for defense in depth. The idea of consolidating connectors and credentials into a single source of authority is a continuation of centralizing connector authorization — part of slowly folding away ad-hoc key handling.
A manageable next step is to switch your local environment to ant auth login and run ant auth status once to see where your credential comes from. When even one key leaves your environment, the operational landscape changes more than you'd expect. Thank you for reading.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.