1# Configuring workload identity federation for SPIFFE
2
3Use SPIFFE as a Workload Identity Provider by exchanging a SPIFFE JWT-SVID for a short-lived OpenAI access token. This lets workloads authenticated by SPIRE or another SPIFFE-compatible identity provider call the OpenAI API without storing long-lived API keys.
4
5OpenAI supports SPIFFE JWT-SVIDs that can be validated as JWT subject tokens with an issuer, audience, expiration, issued-at timestamp, and JWKS-backed signature. OpenAI doesn't support SPIFFE X.509-SVIDs as workload identity federation subject tokens.
6
7The JWT-SVID specification requires the `sub`, `aud`, and `exp` claims. To use a JWT-SVID with OpenAI, the token must also include `iss` and `iat` claims and a `kid` header so OpenAI can validate the token against the Workload Identity Provider configuration.
8
9A JWT-SVID is not an OpenID Connect ID token. The SPIRE OIDC Discovery Provider supplies discovery metadata and JWKS keys so OpenAI can validate the JWT-SVID; it doesn't change the token's SPIFFE semantics or require an OIDC login flow.
10
11For SPIFFE terminology and token requirements, see the SPIFFE [JWT-SVID specification](https://spiffe.io/docs/latest/spiffe-specs/jwt-svid/) and [Workload API specification](https://spiffe.io/docs/latest/spiffe-specs/spiffe_workload_api/).
12
13## Setting up SPIFFE
14
15Configure your SPIFFE provider to issue JWT-SVIDs for workloads that need to call the OpenAI API. These instructions use SPIRE terminology, but the same OpenAI configuration applies to any SPIFFE-compatible provider that emits JWT-SVIDs with issuer and JWKS signing material that OpenAI can validate.
16
17Your SPIFFE setup must provide:
18
19- A stable SPIFFE ID for the workload, such as `spiffe://example.org/ns/production/sa/openai-wif`.
20- A single JWT-SVID audience dedicated to OpenAI access, such as `https://api.openai.com/v1` or another opaque value you choose.
21- A JWT issuer URL that appears in the JWT-SVID `iss` claim for OpenAI validation.
22- A public JWKS for the JWT-SVID signing keys, either through OIDC discovery or an uploaded JWKS.
23- A workload-side way to fetch fresh JWT-SVIDs from the SPIFFE Workload API.
24
25The audience is an exact-match identifier, not necessarily an endpoint that receives the JWT-SVID. You may use `https://api.openai.com/v1` or another service-specific value as long as the SPIFFE Workload API request and OpenAI provider configuration match.
26
27When possible, expose the SPIFFE issuer through your SPIRE OIDC Discovery Provider. Configure the SPIRE Server `jwt_issuer` and the OIDC Discovery Provider `jwt_issuer` to the same HTTPS issuer URL that you will configure in OpenAI.
28
29In the SPIRE Server configuration:
30
31```hcl
32server {
33 trust_domain = "example.org"
34 jwt_issuer = "https://spire-oidc.example.org"
35}
36```
37
38In the separate SPIRE OIDC Discovery Provider configuration:
39
40```hcl
41# Relevant issuer fields only
42domains = ["spire-oidc.example.org"]
43jwt_issuer = "https://spire-oidc.example.org"
44```
45
46The OIDC Discovery Provider configuration also needs a key-material source, such as `server_api`, `workload_api`, or `file`, and a serving mechanism, such as ACME, a TLS certificate, or a Unix socket. See the [SPIRE OIDC Discovery Provider documentation](https://github.com/spiffe/spire/tree/main/support/oidc-discovery-provider) for the complete configuration options.
47
48The SPIFFE trust domain and JWT issuer are different concepts. In this example, the JWT-SVID subject is a SPIFFE ID in the `example.org` trust domain, while the issuer is the HTTPS issuer URL:
49
50```json
51{
52 "sub": "spiffe://example.org/ns/production/sa/openai-wif",
53 "iss": "https://spire-oidc.example.org"
54}
55```
56
57The SPIRE OIDC Discovery Provider serves an OIDC discovery document and a JWKS endpoint that OpenAI can use when **Use uploaded JWKS for token verification** is disabled.
58
59If OpenAI can't reach your issuer discovery endpoint, use uploaded JWKS mode instead. In that mode, OpenAI still compares the Workload Identity Provider issuer with the JWT-SVID `iss` claim, but verifies signatures against the JWKS JSON you save on the Workload Identity Provider.
60
61> **Note:** The SPIFFE JWT-SVID specification makes the JWT header `kid` optional, but OpenAI requires JWT subject tokens to include a `kid` header so it can select the signing key from the configured JWKS. If your SPIFFE provider can omit `kid`, configure it to include one for OpenAI workload identity federation.
62
63To inspect a JWT-SVID from a workload that can call the SPIFFE Workload API, request one for the same audience you will configure in OpenAI. Run this command in the same workload context as the application, because Workload API authorization depends on the identity of the calling process.
64
65```bash
66spire-agent api fetch jwt \
67 -socketPath /run/spire/sockets/agent.sock \
68 -audience "https://api.openai.com/v1"
69```
70
71If your workload has more than one SPIFFE ID, request the specific identity:
72
73```bash
74spire-agent api fetch jwt \
75 -socketPath /run/spire/sockets/agent.sock \
76 -spiffeID "spiffe://example.org/ns/production/sa/openai-wif" \
77 -audience "https://api.openai.com/v1"
78```
79
80## Verify the token
81
82Before configuring workload identity federation, decode a sample JWT-SVID locally and inspect its header and claims:
83
84```bash
85TOKEN="$SPIFFE_JWT_SVID" python3 - <<'PY'
86import base64
87import json
88import os
89
90parts = os.environ["TOKEN"].split(".")
91if len(parts) != 3:
92 raise ValueError("Expected a compact JWT with three segments")
93
94def decode(segment):
95 segment += "=" * (-len(segment) % 4)
96 return json.loads(base64.urlsafe_b64decode(segment))
97
98print("Header:")
99print(json.dumps(decode(parts[0]), indent=2))
100print("\nPayload:")
101print(json.dumps(decode(parts[1]), indent=2))
102PY
103```
104
105This command decodes the JWT without verifying the token signature. Use a local decoder for production tokens, and avoid pasting production tokens into third-party tools.
106
107A decoded SPIFFE JWT-SVID will look similar to:
108
109```json
110{
111 "alg": "ES256",
112 "kid": "jwt-svid-key-1"
113}
114```
115
116```json
117{
118 "iss": "https://spire-oidc.example.org",
119 "aud": ["https://api.openai.com/v1"],
120 "sub": "spiffe://example.org/ns/production/sa/openai-wif",
121 "iat": 1716235422,
122 "exp": 1716235722
123}
124```
125
126Use the decoded token to compare the token you received with the OpenAI configuration before you exchange it. Check `alg` and `kid` in the header, and `iss`, `aud`, `sub`, `iat`, and `exp` in the payload. The exact `alg` value depends on your SPIRE Server JWT signing-key configuration.
127
128## Setting up workload identity federation
129
130Create a Workload Identity Provider in OpenAI for the SPIFFE JWT-SVID issuer, then add a service account mapping that matches the SPIFFE IDs you trust.
131
132### Set up the Workload Identity Provider
133
1341. **Create the Workload Identity Provider.** Set **Name** to a unique value, such as `spiffe-prod`. Use **Description**, such as `Production SPIFFE workloads`, to help admins identify the provider.
135
1362. **Set the issuer and audience.** Set **OIDC Issuer URL** to the exact value of the JWT-SVID `iss` claim, such as `https://spire-oidc.example.org`. Set **Audience** to the audience value requested from the SPIFFE Workload API. In this example, that value is `https://api.openai.com/v1`.
137
1383. **Choose the JWKS source.** Leave **Use uploaded JWKS for token verification** disabled when OpenAI can reach your SPIRE OIDC Discovery Provider. OpenAI uses OIDC discovery and the discovered JWKS to verify JWT-SVID signatures.
139
140 If the issuer isn't reachable from OpenAI, enable **Use uploaded JWKS for token verification**, then set **JWKS JSON** to the public key set for JWT-SVID signing keys. Upload the full public JWKS object, including the surrounding `keys` array. Do not include private key material.
141
1424. **Add attribute transformations only if you need derived mapping attributes.** Attribute transformations aren't required when mapping directly from `sub`. Use them only when you need to derive a mapping value from one or more token claims. See the [main workload identity federation guide](https://developers.openai.com/api/docs/guides/workload-identity-federation#transform-token-claims-with-cel) for transformation behavior.
143
144### Set up the service account mapping
145
1461. **Create a service account mapping.** Set **Name** to a unique value within the Workload Identity Provider, such as `production-openai-wif`. Use **Description**, such as `Production SPIFFE workload for OpenAI API access`, to explain which workload can use the mapping.
147
1482. **Match the SPIFFE ID.** Set **Key** to `sub` and **Value** to the workload's SPIFFE ID, such as `spiffe://example.org/ns/production/sa/openai-wif`.
149
150 Prefer exact SPIFFE ID matching for privileged workloads. Use a trailing wildcard only when every SPIFFE ID under that prefix should be able to mint OpenAI access tokens. For example, `spiffe://example.org/ns/production/sa/*` allows any matching production service account path.
151
1523. **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 SPIFFE workload can use, such as `spiffe-prod-openai-wif`. Check `Create a new service account in this project` if you wish to create a new service account for this mapping rather than reuse an existing one.
153
1544. **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.
155
156## Using the token in code
157
158Configure your OpenAI SDK client to exchange a fresh SPIFFE JWT-SVID for an OpenAI-issued access token.
159
160The SDK samples below assume your SPIFFE integration refreshes a JWT-SVID and writes it to `/var/run/spiffe/openai.jwt`. Keep the file readable only by the workload. Because JWT-SVIDs are short lived, refresh the file before the token expires. As an alternative, use a language-specific SPIFFE library to fetch the JWT-SVID directly from the SPIFFE Workload API in the subject token provider when possible to avoid stale token files.
161
162Set `OPENAI_IDENTITY_PROVIDER_ID` and `OPENAI_SERVICE_ACCOUNT_ID` in the workload environment. The token file contains the external subject token. `OPENAI_IDENTITY_PROVIDER_ID` identifies the OpenAI Workload Identity Provider, and `OPENAI_SERVICE_ACCOUNT_ID` identifies the target OpenAI service account. OpenAI then finds a matching mapping for that provider and service account based on the token claims.
163
164## SPIFFE best practices
165
166- Use JWT-SVIDs for OpenAI workload identity federation. X.509-SVIDs are useful for mutual TLS but aren't accepted by the OpenAI token exchange endpoint.
167- Use a single dedicated audience for OpenAI access. Avoid broad audiences such as a whole trust domain or environment name.
168- Match exact SPIFFE IDs where possible. Use wildcard mappings only for intentionally shared trust boundaries.
169- Keep JWT-SVID lifetimes short to reduce bearer-token replay risk. OpenAI access tokens never outlive the external subject token used for the exchange.
170- Rotate signing keys carefully. Publish both old and new public keys through OIDC discovery during the rotation window, or update the uploaded public JWKS before issuing JWT-SVIDs with a new `kid`.
171- Keep SPIRE Server and workload clocks synchronized. Significant clock skew can cause otherwise valid JWT-SVIDs to be rejected as not yet valid, too old, or expired.
172- Protect the SPIFFE Workload API socket. A process that can fetch a workload's JWT-SVID can attempt to exchange it for OpenAI access.
173- Align OpenAI service account boundaries with your application and environment permission boundaries. Don't share a highly privileged service account across unrelated SPIFFE workloads.
174- Monitor token exchange failures for issuer, audience, signing key, and mapping mismatches.