Replacing Static API Keys With Workload Identity: The Vendor Is the Blocker
A Vercel survey found only 8.4% of more than 1,000 SaaS vendors support short-lived, identity-based auth. Sorting your integrations into three buckets is what makes the rest of the work tractable.
By VVV Ops ·
A Vercel survey of more than 1,000 SaaS vendors, published on 22 October 2026, found that only 8.4% supported secure authentication methods. The other 91.6% can take a long-lived key and nothing else. That number changes the shape of the work. Most teams that still ship static credentials to third parties are waiting on vendors who have no endpoint to federate against, and more work on their own tooling will not move them.
The inbound half of this problem is largely solved and we have written about it before. A CI job can already reach AWS without a key, and Terraform security best practices for AWS covers that setup. Platform-issued tokens inside one vendor's product have their own deadlines, which is what the Azure DevOps global PAT retirement is about. This post is the outbound direction: your workload authenticating to someone else's SaaS, where the vendor decides whether a token is even an option.
What the 8.4% figure measures
Vercel's number comes from a survey it ran of more than 1,000 SaaS vendors, so check the scope before quoting it internally. It counts vendors that support "short-lived, identity-based authentication, whether they accept OIDC tokens directly or exchange them for temporary credentials." The post does not say how support was established for each vendor, so quote it as a survey result with the method unstated.
The enforcement is real and dated. From 30 November 2026, Marketplace vendors that rely on long-lived secrets get a "Not secure" message on their listing. From January 2027, vendors that do not offer secure auth are delisted. Vercel also says it is holding its own API and native integrations to the same bar, which gives the deadline some weight.
Two things follow for anyone who does not sell on that Marketplace. A platform with distribution can force vendor auth to change, so this will not be the last such deadline. And if you run an integration catalogue of any size, the arithmetic says most of it cannot be migrated by you alone.
The three shapes an integration can take
Sorting vendors by what they can accept is the step that makes the rest tractable. There are three cases, and they need different work.
In the first, the vendor validates a JWT your identity provider already signs. You register the issuer with the vendor, write a rule describing which workloads may act as which principal, and your workload presents its ambient token. The work is configuration on the vendor's side plus a trust rule.
In the second, the vendor is the issuer and you are the relying party. Snowflake shipped this shape for outbound calls, generally available on 1 July 2026. Here the vendor hands its workload a signed token and you configure your service to verify it. The work is on your side.
In the third, the vendor has a static key and no roadmap. No amount of work on your side changes that, so the goal moves from elimination to containment.
Count your integrations into those three buckets before touching any configuration. We have found the first bucket is usually larger than teams expect, because several vendors shipped federation in 2026 without anyone on the customer side noticing.
Shape one: your provider's token
GitHub Actions is the most common source for an ambient token, and it needs a job-level permission before the runner will mint one:
permissions:
id-token: write
With that set, the runner exposes ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, and the resulting JWT carries an iss of https://token.actions.githubusercontent.com alongside claims such as repository, environment and job_workflow_ref. Those claim names are what you match on, so read them from GitHub's OIDC reference rather than guessing.
Shape one: the vendor's trust rule
The vendor side has more structure than the phrase "add OIDC support" suggests. Anthropic's Workload Identity Federation is a worked example of what a complete implementation looks like, and it needs three objects rather than one. A service account (svac_...) is the principal a workload acts as. A federation issuer (fdis_...) registers your provider, keyed on the exact iss string and a JWKS source that is discovery, explicit_url or inline. A federation rule (fdrl_...) binds the two, matching on a subject_prefix, an exact audience, a map of claim values, or a CEL condition.
The exchange itself is RFC 7523. Your workload posts the JWT to /v1/oauth/token with grant_type set to urn:ietf:params:oauth:grant-type:jwt-bearer and gets back a short-lived 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": "'"$JWT"'",
"federation_rule_id": "fdrl_...",
"organization_id": "00000000-0000-0000-0000-000000000000",
"service_account_id": "svac_..."
}'
Write the rule narrowly. A subject_prefix that stops at the repository lets any workflow in that repository mint a token, including one added by a pull request. Matching on job_workflow_ref or environment is the difference between a credential scoped to a deploy job and one scoped to a whole repository, and it costs nothing at configuration time.
Shape two: the vendor issues and you verify
The Snowflake direction inverts the ownership. You create a secret whose type says what it is for, and the platform becomes an OIDC provider for that workload (user guide):
CREATE SECRET my_db.auth.my_workload
TYPE = WORKLOAD_IDENTITY_FEDERATION;
DESC SECRET my_db.auth.my_workload; then returns workload_identity_federation_issuer and workload_identity_federation_subject, which are the values your receiving service compares against the token's iss and sub claims. Issuing a token for a specific audience is a function call:
SELECT SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN(
'my_db.auth.my_workload',
'{"aud": "example-cloud-service.com"}');
The trap in this shape is the audience. A service that accepts any aud value will accept a token minted for a different service, which turns a federated setup back into a bearer secret with extra steps. Pin the expected aud, iss and sub on the verifying side, and reject anything else.
The precedence problem that hides an unfinished migration
A static key usually survives a federation rollout because the code path that reads it runs first. Anthropic's SDKs resolve credentials in a fixed order, and ANTHROPIC_API_KEY sits above the federation tiers, so a leftover variable silently wins and the workload keeps using the key while the dashboard shows a working federation rule. The vendor's own migration guidance makes unsetting it a numbered step for that reason.
This generalizes past one vendor. Any SDK with a credential chain will prefer the thing that is cheapest to resolve, which is almost always the environment variable. Two checks are worth building into the cutover rather than discovering later. Assert at startup that the key variable is absent in every place the workload runs, including CI secrets and shell profiles, and fail the deploy if it is set. Then delete the key at the vendor and watch for errors, because a deleted key is the only proof that nothing was still using it.
Token lifetime has a similar quiet edge. In the Anthropic implementation the minted token lives for the lesser of the rule's token_lifetime_seconds (60 to 86400, default 3600) and twice the remaining life of the JWT you presented, floored at 60 seconds. The SDK attempts an advisory refresh at expiry minus 120 seconds and a mandatory one at expiry minus 30 seconds. Short upstream tokens therefore produce short downstream tokens and a refresh loop that runs far more often than the configured lifetime implies, which is easy to miss because nothing fails. Replay protection adds one more: identity tokens carrying a jti are single-use by default, so a retry loop that re-presents a cached JWT fails rather than succeeding twice.
Containing the vendors that will not change
For the third bucket, the work is scoping and blast radius. We would do four things, in this order.
Issue one key per integration per environment, never a shared key across workloads. The moment two services share a key, rotation becomes a scheduling problem across teams and gets deferred indefinitely.
Hold the key in a broker your workloads authenticate to with their platform identity, so the static secret exists in exactly one place. Scoped, expiring credentials handed out by a broker do not remove the vendor's static key, but they stop it being copied into CI secrets, container environments and laptops.
Restrict where the key can be used from. A vendor allowlist on source IP or a dedicated egress address turns a leaked key into a key that only works from your network, which is a meaningful downgrade in severity.
Put the vendor's auth capability in the renewal conversation. Vercel's two dates show that vendors move when a buyer with enough weight asks, and asking costs a line in a procurement questionnaire. Our own posts on MCP server security in production make the same point about scoped tokens from the other end of the integration.
Nothing here requires waiting for the 91.6% to catch up. The first bucket is configuration you can finish this quarter, the second is verification code you already know how to write, and the third shrinks every time a vendor ships federation.
If you want a second pair of eyes on this, tell us what you are running. The first thing we would do is list every outbound credential by the place it is injected, whether a CI secret, a container environment or a broker. The injection points tell you which bucket each vendor sits in, and they are also where a leftover key hides.