Primary navigation

Legacy APIs

Configuring workload identity federation for AWS

Use AWS as a Workload Identity Provider in either of these scenarios:

  • AWS outbound identity federation: Exchange an AWS STS-issued OIDC JWT from GetWebIdentityToken for 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-federation

Record 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))
PY

This 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 the GetWebIdentityToken audience 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

  1. Create the Workload Identity Provider. Set Name to a unique value, such as aws-outbound-prod. Use Description, such as Production AWS outbound identity federation workloads, to help admins identify the provider.

  2. 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 iss claim. Set Audience to the same audience passed to GetWebIdentityToken. In this example, that value is https://api.openai.com/v1.

  3. 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.

  4. Add attribute transformations only if you need derived mapping attributes. Raw token matching supports top-level scalar claims such as sub, aud, and iss. AWS-specific namespaced claims are nested under https://sts.amazonaws.com/, so create derived attributes with CEL bracket notation before using them in mappings. For example, enter aws_environment with expression assertion["https://sts.amazonaws.com/"]["principal_tags"]["environment"] to create openai.aws_environment from 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 with openai. are ignored for openai. mapping keys unless a matching transformation is configured.

Set up the service account mapping

  1. 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 as Production AWS role for OpenAI API workload, to explain which workload can use the mapping.

  2. Match the AWS principal. Set Key to sub and Value to the IAM principal ARN from the decoded token, such as arn:aws:iam::123456789012:role/OpenAIWifRole. Matching on the exact sub claim provides the strongest isolation for AWS outbound identity federation.

  3. 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.

  4. 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.

  5. Narrow API permissions if needed. Select appropriate Permissions such as api.model.request and api.vector_store.read to 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.

Authenticate from an AWS-issued OIDC 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);

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.