Skip to main content
Workload identity federation lets a program running outside TextQL, such as a GitHub Actions job, a Cloud Run service or a Kubernetes pod, authenticate as a service account using the token its platform already gives it. There is no API key to create, store as a secret, or rotate. The workload trades its platform token for a TextQL access token that lasts at most one hour. TextQL accepts the trade only when the token comes from an issuer you registered and matches a federation rule you wrote.
Workload identity federation is in beta and off by default. An organization admin turns it on under Settings → Security → Authentication → Token exchange (Beta). The same switch controls member token exchange.

How It Works

  1. You register an issuer: the system that signs your workload’s tokens, such as https://token.actions.githubusercontent.com.
  2. You create a federation rule on that issuer: the audience the token must carry, the claims it must have (for example “this repository, this branch”), and the service account it then acts as.
  3. The workload gets a token from its platform and sends it to POST /oauth/token. TextQL checks the signature against the issuer’s keys, checks the token’s lifetime, finds the one rule the token matches, and returns an access token for that rule’s service account.
  4. The workload calls TextQL with that access token until it expires, then exchanges a new platform token.
The access token acts as the service account in full, bounded by the access the rule grants (read only, or read and write). Everything it does is attributed to the service account in the audit log.

Set It Up

Open Settings → Developers → Workload Identity and click Connect Workload. The wizard walks through four steps:
  1. Issuer. Pick an issuer you already registered, or choose a provider (GitHub Actions, AWS, Google Cloud, Microsoft Entra, Kubernetes or Custom OIDC) to register one.
  2. Federation rule. Name the rule, confirm the audience, and add claim conditions. Each provider suggests the conditions that identify your workload.
  3. Target. Pick the service account, the access level, and how long issued tokens last (1 minute to 1 hour).
  4. Test. Copy the setup snippet for your provider, and optionally paste a real token from your workload to see whether it would be accepted.
You need the organization:write permission to register issuers and manage rules. Members with organization:read can view them. When you create an API key for a service account and workload identity is available, TextQL first suggests setting up federation instead.

Issuers

An organization can register up to 50 issuers.

Public Issuers

Some issuers sign tokens for anyone who asks. Every GitHub repository can get a token from GitHub Actions, and every Google account can get one from Google. A rule on these issuers must include an exact match on a claim that identifies your own account, or anyone else’s workload could match it. Prefer numeric IDs such as repository_owner_id: a name can be claimed by someone else after a rename. Issuers that belong to one account, such as an AWS account’s STS issuer, a Microsoft Entra tenant or your own Kubernetes cluster, are not public. Their rules still need at least one condition.

Federation Rules

The claims iss, aud, exp, iat, nbf and jti are checked on every exchange and cannot be conditions. If more than one rule accepts a token, the exchange is refused until the workload names a rule with federation_rule_id (or TEXTQL_FEDERATION_RULE_ID in the CLI). An organization can have up to 200 rules. Deleting an issuer deletes its rules. Deleting a service account deletes the rules that target it. Access tokens that were already issued stay valid until they expire, at most one hour later.

Provider Setup

The wizard shows a ready-to-copy snippet for the rule you just created. The examples below show the same setup.

GitHub Actions

Register https://token.actions.githubusercontent.com and match repository_owner_id exactly, plus sub for the repository and branch.
Inside GitHub Actions, the CLI requests the job’s token itself when TEXTQL_ORG_ID is set.

Google Cloud

Register https://accounts.google.com and match the service account’s email exactly. Google’s identity tokens have no jti claim, so turn off Single-use tokens for this issuer (the wizard does this for you). On GCE, GKE (with Workload Identity), Cloud Run and Cloud Functions, the CLI reads the token from the metadata server:

AWS

Turn on outbound web identity federation under IAM → Account settings and register the token issuer URL it shows. Match sub on the role ARN. Turning federation on does not let a role request tokens. Allow sts:GetWebIdentityToken in the workload role’s IAM policy:
Then request a token for the rule’s audience before running the CLI:
On EKS, use the Kubernetes setup with the cluster’s OIDC issuer instead.

Kubernetes

Register the cluster’s service account issuer (kubectl get --raw /.well-known/openid-configuration shows it). If its keys are not reachable from the internet, choose Inline keys and paste the output of kubectl get --raw /openid/v1/jwks. Match sub exactly, as system:serviceaccount:<namespace>:<name>. Mount a projected token for the rule’s audience and point the CLI at it:

Microsoft Entra

Register your tenant’s v2.0 issuer, https://login.microsoftonline.com/<tenant id>/v2.0, and match sub on the managed identity’s object ID. Entra tokens have no jti claim, so turn off Single-use tokens for this issuer (the wizard does this for you). Write a token for your app registration’s audience to a file and set TEXTQL_FEDERATION_TOKEN_FILE.

Any Other OIDC Issuer

Choose Custom OIDC, register the issuer, and add conditions that only your workloads satisfy.

Using the Token

With the CLI

The refinery CLI uses workload identity when TEXTQL_ORG_ID is set together with a token source: TEXTQL_API_KEY still takes precedence when set. With a token file, the CLI keeps the access token in its configuration directory until it expires, so later commands in the same job reuse it instead of exchanging the same single-use token again.

Over HTTP

Exchange the token with a standard RFC 8693 request:
Send the access token as Authorization: Bearer <token> on API requests. Add scope=api:read to the exchange to ask for read-only access.

Testing a Token

On the Workload Identity tab, open a rule’s menu and choose Test token, then paste a token your workload received. TextQL runs every check the exchange runs (issuer, signature, lifetime, audience, each condition, the service account, and whether the token was already used) and shows which pass, along with the token’s decoded claims. Testing issues nothing and does not use up a single-use token.

Troubleshooting

Audit Log