Workload identity federation
Purpose and Scope
Workload identity federation lets an automated workload authenticate to OpenAI without storing a long-lived OpenAI API key in that workload environment. Instead, the workload obtains a short-lived subject token from its own identity provider, such as a cloud metadata service, a Kubernetes projected service account token, or a GitHub Actions OIDC token. The SDK-side implementation then exchanges that subject token for an OpenAI access token and reuses the access token until it expires or approaches its refresh window.
In this SDK, the workload identity implementation is intentionally provider-agnostic. The OpenAI client does not need to know whether the subject token came from GitHub Actions, Google Cloud, Google Kubernetes Engine, a self-managed Kubernetes cluster, Azure, AWS, or a SPIFFE-style workload identity system. It only requires a configured provider object capable of returning a token, plus OpenAI identifiers that tell the token exchange endpoint which Workload Identity Provider and service account are being used. Sources: src/auth/workload-identity-auth.ts
Relevant Source Files
- src/auth/workload-identity-auth.ts — Defines
WorkloadIdentityAuth, the token exchange request, subject token type mapping, access-token cache, refresh behavior, and error handling for workload identity authentication.
Core Concepts
A subject token is the identity token issued by the workload platform. For GitHub Actions, this is a GitHub-issued OIDC JWT requested by a job with id-token: write. For Google Cloud, it can be an identity token from the metadata server for an attached service account. For Kubernetes, it should be an OIDC-compatible projected service account token, not a legacy service account Secret. The SDK accepts this platform-issued token through the configured provider’s getToken() method and treats it as input to OpenAI’s token exchange flow.
The OpenAI access token is the credential returned by the OpenAI authorization service after the subject token is validated. The implementation posts to https://auth.openai.com/oauth/token using the OAuth token exchange grant type, includes the subject token, and sends identifiers for the configured OpenAI workload identity provider and service account. The returned access_token becomes the bearer-style credential that downstream OpenAI API requests can use. Sources: src/auth/workload-identity-auth.ts
The SDK distinguishes two subject token formats through provider.tokenType. A value of jwt maps to the OAuth token type URN for JWTs, while id maps to the URN for ID tokens. This distinction matters because different identity platforms name their tokens differently, but OpenAI’s exchange endpoint receives a standard subject_token_type. The configuration also supports an optional clientId, which is added to the exchange request only when present, and an optional refreshBufferSeconds, which controls proactive refresh behavior. Sources: src/auth/workload-identity-auth.ts
Execution Flow
The runtime flow starts when authentication code asks WorkloadIdentityAuth for a token. If there is no cached token, or the cached token has reached its expiration timestamp, getToken() performs a refresh. If another caller has already started a refresh, the method awaits the existing promise rather than starting a duplicate exchange. This concurrency guard is important in serverless, web, and worker-like environments where many requests may arrive at the same time after a cold start or credential expiration. Sources: src/auth/workload-identity-auth.ts
During refresh, the configured provider is responsible for obtaining the platform token. That provider may call a metadata server, read a projected token file, request a GitHub Actions OIDC token, or integrate with another identity system. After the subject token is available, the SDK builds a JSON body containing grant_type, subject_token, subject_token_type, identity_provider_id, and service_account_id. It then sends a POST request with Content-Type: application/json to the OpenAI token exchange URL. Sources: src/auth/workload-identity-auth.ts
When the exchange succeeds, the implementation validates that the response is an object containing a non-empty string access_token. It reads expires_in when supplied and otherwise defaults the token lifetime to 3600 seconds. The cache stores both the token and an absolute expiration time calculated from the current clock. Later calls return the cached token until it is expired, while calls inside the refresh buffer can return the current token and trigger a background refresh for future calls. Sources: src/auth/workload-identity-auth.ts
// Conceptual shape of a workload identity provider used by the SDK.
const auth = new WorkloadIdentityAuth({
identityProviderId: 'wif-provider-id',
serviceAccountId: 'openai-service-account-id',
provider: {
tokenType: 'jwt',
async getToken() {
return await readPlatformOidcToken();
},
},
refreshBufferSeconds: 1200,
});
const accessToken = await auth.getToken();Provider Patterns
GitHub Actions is a common federation source for CI/CD. A workflow should request permission to mint an OIDC token and use the exact audience configured in the OpenAI Workload Identity Provider. The SDK does not itself call GitHub’s OIDC endpoint; that responsibility belongs to the provider object passed into workload identity configuration. Once the provider returns the GitHub-issued token, the SDK performs the same OpenAI exchange and cache flow used for every other platform.
Google Cloud and Google Kubernetes Engine follow the same SDK contract but differ in how the subject token is obtained. A Google-managed workload can request an identity token from the metadata server for an attached service account, while GKE may use a projected service account token. Kubernetes clusters should use OIDC-compatible projected tokens with an issuer, audience, signature, and expiration that match the OpenAI provider configuration. In all cases, platform setup ensures the token is valid; the SDK handles exchange and refresh. Sources: src/auth/workload-identity-auth.ts
For AWS, Azure, and SPIFFE-style deployments, the key integration point remains the configured subject-token provider. The SDK implementation does not hard-code platform names, metadata URLs, or claim mappings. That design allows cloud-specific or infrastructure-specific code to stay close to the deployment environment while the OpenAI SDK owns the standardized token exchange behavior. The practical requirement is that the provider returns a token matching the configured OpenAI workload identity provider’s expected issuer, audience, token type, and trust rules.
API Components and Behavior Reference
| Component | Contract | Behavior |
|---|---|---|
WorkloadIdentityAuth | Constructed with WorkloadIdentity config and optional fetch | Coordinates token caching, refresh, and exchange |
getToken() | Returns Promise<string> | Returns cached access token, waits for in-flight refresh, or starts a refresh |
provider.getToken() | Returns the platform subject token | Called only during refresh, before the OpenAI token exchange request |
provider.tokenType | jwt or id | Maps to OAuth token type URNs for JWT or ID token exchange |
identityProviderId | OpenAI workload identity provider identifier | Sent as identity_provider_id in the exchange body |
serviceAccountId | OpenAI service account identifier | Sent as service_account_id in the exchange body |
clientId | Optional client identifier | Included in the exchange body only when configured |
refreshBufferSeconds | Optional proactive refresh buffer | Defaults to 1200 seconds when not specified |
invalidateToken() | Clears cached credential state | Forces a later getToken() call to perform a fresh exchange |
The error model separates authorization failures from other exchange failures. If the exchange response is not successful and the status is 400, 401, or 403, the SDK raises an OAuthError with the parsed response body and headers. Other non-success statuses are converted with APIError.generate, using a message that includes the failed status. If the response succeeds but does not contain a usable access_token, the SDK raises OpenAIError to signal an invalid token exchange response shape. Sources: src/auth/workload-identity-auth.ts
Operational Guidance
Keep the provider-specific token acquisition code small, auditable, and aligned with your platform’s security model. GitHub workflows should request only the permissions needed to obtain an OIDC token and use the audience configured in OpenAI. Kubernetes workloads should mount projected service account tokens with a bounded expiration and matching audience. Cloud-managed workloads should prefer metadata-service identity tokens over downloaded service account keys. These practices preserve the main security benefit of workload identity federation: no long-lived OpenAI secret is stored in source control, CI secrets, container images, or local files.
When debugging, separate provider-token failures from OpenAI exchange failures. If provider.getToken() cannot retrieve a token, inspect platform permissions, mounted token files, metadata server access, issuer, audience, and job permissions before looking at SDK exchange behavior. If the OpenAI exchange returns an OAuth status, inspect the configured identityProviderId, serviceAccountId, token type, issuer, audience, and attribute mapping. If concurrency or expiry behavior is involved, remember that the SDK shares an in-flight refresh and proactively refreshes within the configured buffer. Sources: src/auth/workload-identity-auth.ts
Next Steps
After configuring workload identity, wire the resulting authentication flow into normal OpenAI client construction in the same environment that obtains the subject token. For CI systems, start with the GitHub Actions OIDC setup. For hosted workloads, configure the cloud or Kubernetes identity provider first, then implement the provider object that returns the short-lived subject token. Related pages to read next are client configuration and authentication for general client options, deployment and data controls for production environment concerns, and Azure OpenAI or AWS Bedrock if your deployment also uses provider-specific SDK integrations.