Use AWS as a Workload Identity Provider in either of these scenarios:
- AWS outbound identity federation: Exchange an AWS STS-issued OIDC JWT from
GetWebIdentityTokenfor a short-lived OpenAI access token. - Amazon EKS: Exchange a projected Amazon EKS service account token for a short-lived OpenAI access token.
OpenAI supports AWS-issued OIDC JWTs from outbound identity federation and Kubernetes projected service account tokens issued by Amazon EKS. OpenAI does not support SigV4-signed requests or AWS STS temporary access key credentials as workload identity federation subject tokens.
AWS outbound identity federation
AWS outbound identity federation lets an AWS principal request a signed OIDC JWT from AWS STS and present that token to an external service. In OpenAI workload identity federation, the AWS-issued JWT is the subject token that OpenAI validates before issuing an OpenAI access token.
Setting up AWS outbound identity federation
Enable outbound identity federation for the AWS account that will issue tokens. For setup details, see the AWS guide to getting started with outbound identity federation.
aws iam enable-outbound-web-identity-federationRecord the account-specific issuer URL returned by AWS. You will configure this value as the OpenAI Workload Identity Provider issuer, and it must match the iss claim in AWS-issued tokens.
The AWS STS GetWebIdentityToken API is not available on the STS global
endpoint. Configure the AWS CLI or SDK to use a regional STS endpoint.
Grant the workload permission to call sts:GetWebIdentityToken. Restrict the audience and maximum token lifetime in IAM so the AWS principal can mint only tokens intended for OpenAI. This example allows tokens for the audience https://api.openai.com/v1 with a maximum lifetime of 300 seconds:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:GetWebIdentityToken",
"Resource": "*",
"Condition": {
"ForAllValues:StringEquals": {
"sts:IdentityTokenAudience": "https://api.openai.com/v1"
},
"NumericLessThanEquals": {
"sts:DurationSeconds": 300
}
}
}
]
}Request an AWS-issued OIDC token with the same audience you will configure on the OpenAI Workload Identity Provider. Use ES384 unless your environment requires RS256 compatibility.
1
2
3
4
5
6
7
8
TOKEN=$(aws sts get-web-identity-token \
--audience "https://api.openai.com/v1" \
--signing-algorithm ES384 \
--duration-seconds 300 \
--tags Key=environment,Value=production \
Key=workload,Value=batch-ingest \
--query "WebIdentityToken" \
--output text)Verify the AWS-issued token
Before configuring workload identity federation, decode a sample AWS-issued token locally and inspect its claims:
1
2
3
4
5
6
7
8
9
TOKEN="$TOKEN" python3 - <<'PY'
import base64
import json
import os
payload = os.environ["TOKEN"].split(".")[1]
payload += "=" * (-len(payload) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(payload)), indent=2))
PYThis command decodes the JWT payload without verifying the token signature. Use a local decoder for production tokens, and avoid pasting production tokens into third-party tools.
A decoded AWS-issued OIDC token will look similar to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"iss": "https://abc123-def456-ghi789-jkl012.tokens.sts.global.api.aws",
"aud": "https://api.openai.com/v1",
"sub": "arn:aws:iam::123456789012:role/OpenAIWifRole",
"iat": 1716235422,
"exp": 1716235722,
"jti": "jwt-id-example",
"https://sts.amazonaws.com/": {
"aws_account": "123456789012",
"source_region": "us-west-2",
"org_id": "o-exampleorgid",
"principal_tags": {
"environment": "production"
},
"request_tags": {
"environment": "production",
"workload": "batch-ingest"
}
}
}Not every AWS-issued token contains every AWS-specific claim. The claims under https://sts.amazonaws.com/ depend on the calling principal, session context, and request tags.
Verify the claims you plan to configure in OpenAI:
iss: Must match the AWS account-specific issuer URL configured in the OpenAI Workload Identity Provider.aud: Must match theGetWebIdentityTokenaudience and the OpenAI Workload Identity Provider audience.sub: Identifies the IAM principal ARN that requested the token. Prefer matching the exact role ARN.- AWS-specific claims: Use the decoded token as the source of truth before matching account, organization, principal tag, or request tag values.
Use the decoded payload to compare the token you received with the issuer, audience, and mapping values configured in OpenAI. Most configuration issues are visible in the iss, aud, and sub claims before you exchange the token.
Setting up workload identity federation
Create a Workload Identity Provider in OpenAI for the AWS account issuer, then add a service account mapping that matches stable claims from the AWS-issued token.
Configure the Workload Identity Provider first, then create the service account mapping.
Set up the Workload Identity Provider
-
Create the Workload Identity Provider. Set Name to a unique value, such as
aws-outbound-prod. Use Description, such asProduction AWS outbound identity federation workloads, to help admins identify the provider. -
Set the issuer and audience. Set OIDC Issuer URL to the AWS account-specific issuer URL returned when outbound identity federation was enabled. This value must match the token’s
issclaim. Set Audience to the same audience passed toGetWebIdentityToken. In this example, that value ishttps://api.openai.com/v1. -
Use AWS OIDC discovery. Leave Use uploaded JWKS for token verification disabled. OpenAI uses the AWS issuer’s OIDC discovery metadata and JWKS to verify the AWS-issued token.
-
Add attribute transformations only if you need derived mapping attributes. Raw token matching supports top-level scalar claims such as
sub,aud, andiss. AWS-specific namespaced claims are nested underhttps://sts.amazonaws.com/, so create derived attributes with CEL bracket notation before using them in mappings. For example, enteraws_environmentwith expressionassertion["https://sts.amazonaws.com/"]["principal_tags"]["environment"]to createopenai.aws_environmentfrom the decoded token example above. Verify the nested claim path in a sample token before using it; if a transformation cannot be evaluated, mapping resolution fails. Raw token claims that already start withopenai.are ignored foropenai.mapping keys unless a matching transformation is configured.
Set up the service account mapping
-
Create a service account mapping. Set Name to a value that is unique within the Workload Identity Provider, such as
aws-role-openai-wif. Use Description, such asProduction AWS role for OpenAI API workload, to explain which workload can use the mapping. -
Match the AWS principal. Set Key to
suband Value to the IAM principal ARN from the decoded token, such asarn:aws:iam::123456789012:role/OpenAIWifRole. Matching on the exactsubclaim provides the strongest isolation for AWS outbound identity federation. -
Add additional claim matches if needed. You can match on any available scalar claim or transformed attribute. For example, use transformed attributes derived from AWS account, organization, principal tag, or request tag claims if you need additional trust boundaries.
-
Choose the OpenAI target. Set Project to the OpenAI project that owns the target service account. Set Service account to the OpenAI service account the AWS workload can use, such as
aws-outbound-prod-openai-wif. -
Narrow API permissions if needed. Select appropriate Permissions such as
api.model.requestandapi.vector_store.readto further narrow access tokens minted from this mapping. Leave permissions blank to avoid adding a WIF-specific scope restriction; the token still authorizes as the mapped service account.
Using the token in code
Configure your OpenAI SDK client to request an AWS-issued OIDC token from AWS STS and exchange it for an OpenAI-issued access token.
Set OPENAI_WIF_AUDIENCE to the same audience configured on the OpenAI Workload Identity Provider. The subject token provider calls AWS STS GetWebIdentityToken with that audience, returns the AWS-issued JWT as the subject token, and the OpenAI SDK exchanges it for an OpenAI-issued access token.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { GetWebIdentityTokenCommand, STSClient } from "@aws-sdk/client-sts";
import OpenAI from "openai";
import type { SubjectTokenProvider } from "openai/auth";
const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;
const audience = process.env.OPENAI_WIF_AUDIENCE;
const awsRegion = process.env.AWS_REGION;
if (!identityProviderId || !serviceAccountId || !audience || !awsRegion) {
throw new Error(
"Set OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID, OPENAI_WIF_AUDIENCE, and AWS_REGION"
);
}
const sts = new STSClient({ region: awsRegion });
function awsOutboundWebIdentityTokenProvider(): SubjectTokenProvider {
return {
tokenType: "jwt",
getToken: async () => {
const response = await sts.send(
new GetWebIdentityTokenCommand({
Audience: [audience],
SigningAlgorithm: "ES384",
DurationSeconds: 300,
})
);
if (!response.WebIdentityToken) {
throw new Error("AWS STS did not return a web identity token.");
}
return response.WebIdentityToken;
},
};
}
const client = new OpenAI({
workloadIdentity: {
identityProviderId,
serviceAccountId,
provider: awsOutboundWebIdentityTokenProvider(),
},
});
const response = await client.responses.create({
model: "gpt-4.1-mini",
input: "Say hello from AWS outbound workload identity federation.",
});
console.log(response.output_text);Amazon EKS projected service account tokens
Use Amazon EKS as a Workload Identity Provider by exchanging an EKS-issued projected service account token for a short-lived OpenAI access token.
Setting up EKS
Use a Kubernetes ServiceAccount for the EKS workload that needs to call the OpenAI API. If you do not already have one, create it:
kubectl create serviceaccount openai-wif --namespace defaultEKS projected service account tokens use a sub claim in the format system:serviceaccount:<namespace>:<service-account-name>. For the service account above, the sub claim is system:serviceaccount:default:openai-wif.
Retrieve the OIDC issuer URL associated with the EKS cluster:
1
2
3
4
5
aws eks describe-cluster \
--name <cluster-name> \
--region <region> \
--query "cluster.identity.oidc.issuer" \
--output textExample output:
https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3The issuer you configure in the OpenAI Workload Identity Provider must match this issuer URL and the iss claim in the projected EKS service account token.
Configure the projected service account token with the audience OpenAI expects and an expiration suitable for your workload. OpenAI validates the token’s issuer, signature, audience, and expiration. In this example, the token file is mounted at /var/run/secrets/tokens/token, uses the audience https://api.openai.com/v1, and expires after 3600 seconds. You may use a different audience if the projected token audience and OpenAI Workload Identity Provider audience match:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
name: openai-wif-app
namespace: default
spec:
serviceAccountName: openai-wif
containers:
- name: app
image: my-image
volumeMounts:
- name: eks-sa-token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
- name: eks-sa-token
projected:
sources:
- serviceAccountToken:
path: token
audience: "https://api.openai.com/v1"
expirationSeconds: 3600Verify the EKS token
Before configuring workload identity federation, decode a sample projected service account token locally and inspect its claims. From a running pod with the projected token mounted:
1
2
3
4
5
6
7
8
9
10
11
TOKEN=$(kubectl exec -n default openai-wif-app -- cat /var/run/secrets/tokens/token)
TOKEN="$TOKEN" python3 - <<'PY'
import base64
import json
import os
payload = os.environ["TOKEN"].split(".")[1]
payload += "=" * (-len(payload) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(payload)), indent=2))
PYThis command decodes the JWT payload without verifying the token signature. Use a local decoder for production tokens, and avoid pasting production tokens into third-party tools.
A decoded EKS projected service account token will look similar to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"iss": "https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3",
"aud": ["https://api.openai.com/v1"],
"sub": "system:serviceaccount:default:openai-wif",
"iat": 1716235422,
"exp": 1716239022,
"kubernetes.io": {
"namespace": "default",
"serviceaccount": {
"name": "openai-wif",
"uid": "11111111-2222-3333-4444-555555555555"
}
}
}Use the decoded payload to compare the token you received with the issuer, audience, and mapping values configured in OpenAI. Most configuration issues are visible in the iss, aud, and sub claims before you exchange the token.
Setting up workload identity federation
Create a Workload Identity Provider in OpenAI for the EKS issuer, then add a service account mapping that matches attributes from the projected token.
Configure the Workload Identity Provider first, then create the service account mapping.
Set up the Workload Identity Provider
-
Create the Workload Identity Provider. Set Name to a unique value, such as
aws-eks-prod. Use Description, such asProduction EKS cluster, to help admins identify the cluster. -
Set the issuer and audience. Set OIDC Issuer URL to the issuer returned by
aws eks describe-cluster --query "cluster.identity.oidc.issuer". This value must match theissclaim in the projected EKS service account token. Set Audience to the same audience configured on the projected service account token volume. In this example, that value ishttps://api.openai.com/v1. -
Use EKS OIDC discovery. Leave Use uploaded JWKS for token verification disabled. OpenAI uses the EKS issuer’s OIDC discovery metadata and JWKS to verify the projected service account token.
-
Add attribute transformations only if you need derived mapping attributes. Raw token claims such as
sub,aud, andisscan be used directly in mapping assertions. For example, create a transformed attribute namedsubjectwith expressionassertion.sub. In the dashboard, entersubjectas the attribute name; OpenAI stores it asopenai.subject, which you can reference in mappings.Note: Raw token claims that already start with
openai.are ignored foropenai.mapping keys unless a matching transformation is configured.
Set up the service account mapping
-
Create a service account mapping. Set Name to a unique value within the Workload Identity Provider, such as
openai-mapping-eks. Use Description, such asWorkload Identity Provider Mapping for EKS Workloads, to explain which workload can use the mapping. -
Match the EKS service account subject. Set Key to
suband Value tosystem:serviceaccount:default:openai-wif. You can match on any available claim or transformed attribute. Matching onsubis the most restrictive option because it uniquely identifies a Kubernetes service account. -
Choose the OpenAI target. Set Project to the OpenAI project that owns the target service account. Set Service account to the OpenAI service account the EKS workload can use, such as
aws-eks-prod-openai-wif. CheckCreate a new service account in this projectif you wish to create a new service account for this mapping rather than reuse an existing one. -
Narrow API permissions if needed. Select appropriate Permissions such as
api.model.requestandapi.vector_store.readto further narrow access tokens minted from this mapping. Leave permissions blank to avoid adding a WIF-specific scope restriction; the token still authorizes as the mapped service account.
Using the token in code
Configure your OpenAI SDK client to read the projected EKS service account token and exchange it for an OpenAI-issued access token.
Use the mounted token path, such as /var/run/secrets/tokens/token, as the subject token source for the SDK workload identity federation provider. The SDK exchanges that EKS token for an OpenAI-issued access token and uses the OpenAI token to authenticate API requests.
The following examples initialize an OpenAI client with a custom subject token provider. The provider reads the projected EKS service account token from the mounted file path and uses it as the subject token for workload identity federation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { readFile } from "node:fs/promises";
import OpenAI from "openai";
import type { SubjectTokenProvider } from "openai/auth";
const tokenPath = "/var/run/secrets/tokens/token";
const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;
if (!identityProviderId || !serviceAccountId) {
throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");
}
function mountedEksServiceAccountTokenProvider(path: string): SubjectTokenProvider {
return {
tokenType: "jwt",
getToken: async () => {
const token = (await readFile(path, "utf8")).trim();
if (!token) {
throw new Error("The mounted EKS service account token file is empty.");
}
return token;
},
};
}
const client = new OpenAI({
workloadIdentity: {
identityProviderId,
serviceAccountId,
provider: mountedEksServiceAccountTokenProvider(tokenPath),
},
});
const response = await client.responses.create({
model: "gpt-4.1-mini",
input: "Say hello from AWS workload identity federation.",
});
console.log(response.output_text);AWS best practices
- Use a dedicated AWS identity per workload. Use separate IAM roles for AWS outbound identity federation and separate Kubernetes service accounts for EKS workloads.
- Configure a dedicated audience for OpenAI access. Use the same audience value in the AWS-issued or EKS projected token and in the OpenAI Workload Identity Provider configuration.
- Keep token lifetimes reasonably short. For AWS outbound identity federation, use IAM conditions such as
sts:DurationSeconds; for EKS, set an appropriate projected token expiration. - Prefer exact subject matching. Match on the full IAM principal ARN for AWS outbound tokens or the full Kubernetes service account subject for EKS tokens.
- Scope mappings to stable boundaries. Use account, organization, namespace, or transformed attributes when they reduce access without creating broad trust rules.
- Reload tokens when exchanging them. Request AWS outbound tokens when needed, and read EKS projected tokens from the mounted file path so rotated tokens are picked up automatically.
- Grant only the permissions required by the workload. Use mapping-level permissions to further narrow access granted by the target OpenAI service account.