Skip to main content
Workload identity federation lets a workload call the Reducto API without a long-lived API key. The workload sends a short-lived token from its platform (GitHub Actions, Kubernetes, AWS, Azure, Google Cloud and others) to Reducto. Reducto verifies the token and returns a short-lived Reducto access token. The workload uses that access token in place of an API key. Use workload identity federation when:
  • A CI workflow calls Reducto, and you do not want a Reducto API key in your repository secrets.
  • A service runs on Kubernetes, a cloud VM or a serverless runtime that already has a platform identity.
  • Your security team requires that no long-lived credentials sit in secret stores or environment variables.
  • You want to limit Reducto access to one repository, branch, service account or cloud role.

Concepts

How it works

An Owner or Admin of your Reducto organization configures two things before the workload runs:
  1. An identity provider with the issuer URL, the audience, and the key source that Reducto uses to verify signatures.
  2. One or more mappings with the claim values that a token must have.
At runtime:
  1. The workload gets a subject token from its platform, with the audience you configured.
  2. The workload sends the subject token and the identity provider ID to POST https://platform.reducto.ai/oauth/token.
  3. Reducto verifies the signature, issuer, audience and expiry, then evaluates the provider’s mappings. Exactly one enabled mapping must match.
  4. Reducto returns an access token for your organization. It expires in one hour or less.
  5. The workload calls the Reducto API with Authorization: Bearer <access token>. Before the token expires, the workload exchanges a fresh subject token again.
The Reducto Python and Node.js SDKs do steps 2, 4 and 5 for you. You give the SDK the identity provider ID and a function that returns a subject token.
X.509 certificate federation (mutual TLS client certificates) is not supported yet. Use an OIDC JWT or a SPIFFE JWT-SVID.

Choose a setup guide

Each guide shows how to get a token on that platform, what its claims look like, which provider and mapping values to set, and the SDK code.

GitHub Actions

OIDC tokens for CI and deploy workflows.

Kubernetes

Projected service account tokens in self-managed clusters.

AWS

Outbound identity federation and Amazon EKS.

Microsoft Azure

Managed identity tokens and AKS.

Google Cloud

Metadata server identity tokens and GKE.

Oracle Cloud Infrastructure

Instance principal tokens from an identity domain.

SPIFFE

JWT-SVIDs from SPIRE or another SPIFFE provider.

Idira

JWT-SVIDs from Idira Secure Workload Access.
Any other issuer works if it signs standard JWTs with a JWKS that it publishes or that you upload. Use the fields below with the issuer’s values.

Set up workload identity federation in Studio

You must be an Owner or Admin of the organization. See Roles & Permissions.
1

Open the workload identity settings

In Studio, open Settings > Workload identity.
2

Create an identity provider

Click Add provider. Choose a preset for your platform to fill the issuer and audience, or enter them yourself. Save the provider and copy its ID (wip_...).
3

Add a mapping

Open the provider and add a mapping with the claim conditions that a trusted token must have. See Configure mappings.
4

Test a token

Use Test a token to paste a sample subject token. Studio shows the verified claims, the derived attributes, and which mappings match. The test does not issue an access token.
5

Connect the workload

Give the workload the provider ID and update its code. See Connect the workload.

Identity provider options

The audience is an exact-match string. It does not have to be a URL that receives traffic. Use a value that only Reducto accepts, so a token minted for Reducto cannot be replayed to another service, and the reverse.

Key sources

Each provider uses exactly one key source. Discovery and JWKS URLs must use https on port 443 with a public DNS name. Reducto rejects IP addresses, credentials, query strings and fragments in these URLs. It also rejects private host names, such as names without a dot or names that end in .svc, .internal, .local or .lan. An issuer such as https://kubernetes.default.svc needs an uploaded JWKS. Reducto caches discovery documents and JWKS for 600 seconds. If a token has a kid that is not in the cached JWKS, Reducto fetches the JWKS once more before it rejects the token. It fetches the JWKS again at most once every 30 seconds per issuer. When your issuer rotates signing keys, publish the new key before you sign tokens with it. An uploaded JWKS must contain a non-empty keys array of 1 to 20 public keys, each with a unique kid and a kty of RSA, EC or OKP. It must not contain private key material. Update the provider before your issuer signs with a new key. Reducto rejects tokens signed by a key that is not in the uploaded JWKS.

Copy nested claims

An attribute transformation copies one claim into a reducto.* attribute. Use one when the claim you want to match is inside a nested object or a list, such as AWS principal tags or the Kubernetes namespace. Top-level claims need no transformation, because conditions match them directly. Each transformation has two fields:
  • attribute: the attribute name. It is reducto. followed by 1 to 64 lowercase letters, digits and underscores, starting with a letter or underscore. For example, reducto.namespace.
  • claim: the path to the claim, as a list of 1 to 10 segments. The path starts at the top level of the token claims. A string segment is an object key of 1 to 256 characters and can contain dots and slashes. An integer segment of 0 or more is a list index.
The value at the path must be a string, an integer or a boolean. Reducto compares it to a mapping condition as a string: true becomes "true" and 7 becomes "7". If the path does not exist in the token, or the value is a list, an object or null, the exchange fails at the transform stage. Mapping keys that start with reducto. resolve only from transformations. A raw claim named reducto.something in the token has no effect.

Configure mappings

A mapping decides which verified tokens get an access token for your organization. All conditions in a mapping must match. Values match exactly, with one exception: a string value can end with one * after a non-empty prefix. The value then matches any claim that starts with that prefix. If a claim is a list, such as an aud with several values, the condition matches when any item matches. To match a value inside a nested object, copy it to an attribute with a transformation and match on that attribute.

Mapping resolution

Reducto evaluates every enabled mapping under the requested provider. Exactly one mapping must match:
  • If no mapping matches, the exchange fails.
  • If two or more mappings match, the exchange fails. Reducto does not pick one.
Write mappings that do not overlap. For example, do not create both sub: repo:acme/* and sub: repo:acme/payments:* under one provider, because a token from acme/payments matches both. Use a separate provider, or tighter conditions, for each trust boundary.

Example: GitHub Actions deploys from main

A GitHub Actions job in acme/payments gets a token with these claims:
The mapping payments-main has two conditions: Both conditions match, so Reducto issues an access token. A job on a feature branch of the same repository matches sub but not ref, so its exchange fails. A job in acme/web matches neither condition.

Connect the workload

The Reducto SDKs exchange the subject token, cache the access token, and exchange again before it expires. Pass workload_identity (Python) or workloadIdentity (Node.js) with the provider ID and a token provider. The SDKs include token providers for common platforms in reducto.auth and reductoai/auth.

Token providers

The GitHub Actions, AWS and Google Cloud helpers take an audience option that defaults to https://platform.reducto.ai. The Kubernetes helper defaults to /var/run/secrets/kubernetes.io/serviceaccount/token. For Azure, resource defaults to https://management.azure.com/, so set it to your Reducto audience. For any other source, pass your own token provider: an object with token_type ("jwt" or "id") and a get_token function in Python, or tokenType and an async getToken function in Node.js. The SDK calls it each time it needs a fresh subject token. The Oracle Cloud guide shows an example. A failed exchange raises OAuthError with the error and error_description from Reducto. A token provider that cannot return a subject token raises SubjectTokenProviderError. In Python, import both from reducto. In Node.js, import both from reductoai/auth.

Configure with environment variables

The SDKs also read workload identity settings from the environment. With these variables set, Reducto() and new Reducto() need no arguments. Set REDUCTO_IDENTITY_PROVIDER_ID with one of REDUCTO_IDENTITY_TOKEN_FILE or REDUCTO_IDENTITY_TOKEN.

Credential precedence

The SDKs use the first credential they find, in this order:
  1. The api_key / apiKey argument.
  2. The workload_identity / workloadIdentity argument.
  3. The REDUCTO_API_KEY environment variable.
  4. The workload identity environment variables.
Passing both an API key argument and a workload identity argument raises an error.
REDUCTO_API_KEY wins over the workload identity environment variables. When you move a workload from an API key to federation, remove REDUCTO_API_KEY from its container environment, CI secrets and shell profiles. Then delete the old key in Studio.

Token lifetime and renewal

An access token expires at the earliest of:
  • The token lifetime of the mapping (default 3600 seconds).
  • 3600 seconds after issue.
  • The subject token’s exp.
Reducto does not issue refresh tokens. To renew, exchange a fresh subject token. The SDKs renew automatically. They exchange again before expiry, with a buffer of 20 minutes or half the token lifetime, whichever is shorter. Concurrent requests share one exchange. If the API returns HTTP 401, the SDK exchanges once more and retries the request. If you call the exchange endpoint yourself, store access_token with expires_at (a Unix timestamp in seconds) and exchange again a few minutes before that time. expires_in counts from the moment of issue, so network time does not extend it. See the token exchange reference. Cache the access token and use it for every request until shortly before it expires. Do not exchange a token for each API request. The token endpoint has a rate limit per IP address, see Rate limits. Access tokens are revocable. If you disable or delete the provider or the mapping that issued a token, the token stops working within 60 seconds.

Regions

Each Reducto region has its own identity providers, mappings and access tokens. Create the provider in the region your workload calls. A provider ID from one region does not exist in another, and an access token works only in the region that issued it. The SDKs send the exchange to the client’s base_url (baseURL in Node.js), so a client configured for the EU region exchanges in the EU region. The audience is independent of the region. You can use https://platform.reducto.ai as the audience in every region.

Limits

Troubleshooting

Studio lists recent exchanges under Settings > Workload identity > Exchange history, with the outcome and, for failures, the stage and the reason. The token endpoint’s error_description names the failed stage but does not include your configuration values. To inspect a token, decode its payload on the machine that has it. Do not paste production tokens into third-party JWT websites.

HTTP 429 from the token endpoint

Problem: POST /oauth/token returns HTTP 429. Solution: Too many exchanges came from one IP address. Cache each access token until shortly before it expires, and share one client per process. Workloads behind one NAT gateway share the limit. Retry with exponential backoff.

Signature or key errors

Problem: The exchange fails with a signature or key error. Solution: Check that the token header has a kid and an asymmetric alg (RS, PS or ES family). For OIDC discovery, open <issuer>/.well-known/openid-configuration from a public network and confirm that its jwks_uri lists the kid. For an uploaded JWKS, upload the current key set, including any new key.

Issuer or audience mismatch

Problem: The exchange fails at the claims stage. Solution: Compare the token’s iss with the provider issuer character by character (only a trailing slash is ignored). Confirm that the token’s aud contains the provider audience exactly. Most platforms set aud from the audience you request, so request the same value you configured.

Token expired or not yet valid

Problem: Reducto rejects a token that looks valid. Solution: Reducto allows 30 seconds of clock skew. Check the workload’s clock with NTP, and check that the token’s exp is in the future. For tokens on disk, confirm that the file is refreshed.

No mapping matches

Problem: The exchange fails at the mapping stage. Solution: Run Test a token in Studio. It lists each mapping and the conditions that failed. Check for a disabled mapping, a typo in a claim value, or a wildcard in the wrong place.

More than one mapping matches

Problem: The exchange fails although your mapping matches. Solution: Another enabled mapping under the same provider also matches. Test a token lists every match. Tighten or disable one of them so that exactly one matches.

The SDK uses an API key instead

Problem: Requests succeed, but the exchange history is empty. Solution: REDUCTO_API_KEY is set in the environment and takes precedence. Remove it. See Credential precedence.

The API rejects the access token

Problem: The exchange succeeds, but API calls return HTTP 401. Solution: Confirm that the workload calls the same region that issued the token, and that the provider and mapping are still enabled. The same billing and organization checks that apply to API keys also apply to access tokens.

Security recommendations

  • Use a dedicated audience for Reducto, such as https://platform.reducto.ai, and no other service.
  • Create one mapping per workload. Match exact subjects (sub, role ARNs, SPIFFE IDs) instead of broad patterns.
  • Keep production and non-production workloads on separate mappings, or separate providers.
  • Use the shortest token lifetime that fits the workload.
  • Never log subject tokens or access tokens.
  • Review the exchange history for unexpected subjects and repeated failures.
  • Disable and delete providers and mappings that you no longer use.
  • After you move a workload to federation, delete its old API key.