# Configuring workload identity federation for Oracle Cloud Infrastructure

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Use Oracle Cloud Infrastructure (OCI) as a Workload Identity Provider by exchanging an Oracle Identity Cloud Service (IDCS) access token for a short-lived OpenAI access token. An OCI instance principal signs a token exchange request to an identity domain in the same tenancy. OpenAI validates the resulting token and authorizes the OCI workload to act as a mapped OpenAI service account.

For Codex, use this page to get and inspect the Oracle token. Then [configure Codex workload identity](https://developers.openai.com/codex/enterprise/workload-identity) to write that token to a file and point Codex to it. The service-account mapping and SDK examples on this page apply to the OpenAI API.

This setup does not require an OpenAI API key, a custom Oracle OAuth resource application, or dynamic group grants to a custom application.

## Set up the OCI workload

Run your workload on an OCI Compute instance with an instance principal. For Oracle Kubernetes Engine (OKE), confirm which identity signs the request: the standard instance principal signer typically identifies the worker node, not an individual Kubernetes pod.

The signer obtains credentials from the [OCI instance metadata service](https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/gettingmetadata.htm). Verify the workload can reach the link-local metadata endpoint:

```bash
curl --fail --silent \
  --header "Authorization: Bearer Oracle" \
  http://169.254.169.254/opc/v2/instance/id
```

The workload must also be able to make outbound HTTPS requests to the identity domain in its tenancy. The metadata endpoint itself does not require a NAT gateway or an internet connection.

### Request an Oracle identity token

Use `InstancePrincipalsSecurityTokenSigner` from the OCI Python SDK to sign an OAuth token exchange request to your identity domain:

```text
POST https://<identity-domain>/oauth2/v1/token
Content-Type: application/x-www-form-urlencoded;charset=utf-8

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
scope=urn:opc:idm:__myscopes__
requested_token_type=urn:ietf:params:oauth:token-type:access_token
```

The `urn:opc:idm:__myscopes__` scope uses the instance principal's existing authorization. Use the returned IDCS access token as the subject token for OpenAI workload identity federation. Do not replace the Oracle token audience with `https://api.openai.com/v1`; configure the OpenAI provider with an audience that appears in the actual Oracle token.

### Verify the token

Set `TOKEN` to an access token generated by the actual OCI workload, then use the existing local JWT decoder to inspect its claims:

```python
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))
```


The decoder inspects the token without verifying its signature. Treat raw tokens as sensitive, do not log them, and do not paste production tokens into third-party JWT decoders.

A decoded Oracle access token can contain the following claims:

```json
{
  "iss": "https://identity.oraclecloud.com/",
  "aud": [
    "https://idcs-example.us-phoenix-1.identity.oraclecloud.com",
    "https://idcs-example.identity.oraclecloud.com"
  ],
  "sub_type": "instance",
  "ipst_instance": "ocid1.instance.oc1.phx.<instance-id>",
  "ipst_compartment": "ocid1.compartment.oc1..<compartment-id>",
  "domain_id": "ocid1.domain.oc1..<domain-id>",
  "ca_ocid": "ocid1.tenancy.oc1..<tenancy-id>",
  "tenant": "idcs-example",
  "exp": 1782369434,
  "iat": 1782365834
}
```

Use the token issued by your own identity domain as the source of truth. Configure the exact `iss` value and one of the token's `aud` values. Prefer the immutable `ipst_instance`, `ipst_compartment`, `domain_id`, and `ca_ocid` claims when authorizing a workload.

## Set up workload identity federation

Create a Workload Identity Provider for your Oracle identity domain, then add a mapping for the OCI instance or compartment that can use the target OpenAI service account.

### Set up the Workload Identity Provider

1. **Create the Workload Identity Provider.** Set **Name** to a unique value, such as `oracle-cloud-prod`. Use **Description**, such as `Production OCI instance principal`, to identify the trusted workload.

2. **Set the issuer and audience.** Set **OIDC Issuer URL** to the token's `iss` claim, such as `https://identity.oraclecloud.com/`. Set **Audience** to one of the `aud` values in the same token.

3. **Configure tenant-specific OIDC discovery when available.** If **Use custom URL for OIDC discovery** appears under **Advanced**, enable it. Set **Custom OIDC discovery URL** to your tenant-specific identity domain, such as `https://idcs-example.identity.oraclecloud.com`. OpenAI retrieves `https://idcs-example.identity.oraclecloud.com/.well-known/openid-configuration`, then uses the discovery document's `jwks_uri` to retrieve the tenant's public signing keys. If the custom discovery option does not appear, enable **Use uploaded JWKS for token verification** and upload the public JWKS from `https://<identity-domain>/admin/v1/SigningCert/jwk` instead.

4. **Add attribute transformations only when you need derived attributes.** You can use raw Oracle claims such as `ipst_instance`, `ipst_compartment`, `domain_id`, and `ca_ocid` directly in service account mapping assertions. For an explicitly derived instance attribute, enter `instance` with the expression `assertion.ipst_instance` to create `openai.instance`.

Oracle's [OpenID Connect discovery reference](https://docs.oracle.com/en/cloud/paas/identity-cloud/idcsa/op-well-known-openid-configuration-get.html) shows why custom discovery is important: the discovery document can declare the global issuer `https://identity.oraclecloud.com/` while publishing the token endpoint and `jwks_uri` on the tenant-specific identity domain. Keep the global issuer in **OIDC Issuer URL** and use the tenant domain for **Custom OIDC discovery URL**.

If your identity domain publishes discovery metadata at the token issuer,
  leave custom discovery disabled and use standard OIDC discovery. If OpenAI
  cannot reach the tenant discovery document or signing-key endpoint, disable
  custom discovery, enable **Use uploaded JWKS for token verification**, and
  upload the tenant's public JWKS from
  `https://<identity-domain>/admin/v1/SigningCert/jwk`. Custom discovery and
  uploaded JWKS cannot be enabled at the same time. Update uploaded keys when
  Oracle rotates its signing certificates.

### Set up the service account mapping

1. **Create a service account mapping.** Set **Name** to a unique value, such as `oracle-instance-prod`, and add a description that identifies the trusted OCI workload.

2. **Match the narrowest stable OCI identity.** To grant access to one instance, set **Key** to `ipst_instance` and **Value** to the exact instance OCID from the verified token. To grant access to instances across one compartment, set **Key** to `ipst_compartment` and **Value** to the exact compartment OCID.

3. **Add domain and tenancy boundaries when needed.** Add further mapping rows for `domain_id` or `ca_ocid` to limit the workload to a particular Oracle identity domain or tenancy. Add `sub_type` with the value `instance` when the token includes that claim and you want to require an instance principal. All mapping rows must match.

4. **Choose the OpenAI target.** Set **Project** to the project that owns the service account, then select the **Service account** that the trusted OCI workload can use.

5. **Narrow API permissions if needed.** Select only the **Permissions** needed by the workload. Mapping permissions can restrict the selected service account but cannot grant permissions the service account does not already have.

An OKE workload that uses the standard instance principal signer inherits the
  worker node's identity. An instance-level mapping authorizes that node, not
  just one pod. Use a more specific, supported OCI workload identity when you
  need isolation between pods sharing a worker node.

## Use the token in code

Install the OpenAI, OCI, and Requests Python packages:

```bash
pip install openai oci requests
```

Set `OCI_IDENTITY_DOMAIN_URL` to the base URL of the identity domain in the same tenancy as the workload. Set `OPENAI_IDENTITY_PROVIDER_ID` and `OPENAI_SERVICE_ACCOUNT_ID` to the IDs from your OpenAI provider and service account mapping.

The following example signs an Oracle token exchange request with the OCI instance principal, returns the IDCS access token to the OpenAI SDK, and lets the SDK exchange it for a short-lived OpenAI access token when needed:

Authenticate with an OCI instance principal

```python
import os

import oci
import requests
from openai import OpenAI
from openai.auth import SubjectTokenProvider


def oracle_instance_principal_token_provider(
    identity_domain_url: str,
) -> SubjectTokenProvider:
    def get_token() -> str:
        signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
        response = requests.post(
            f"{identity_domain_url.rstrip('/')}/oauth2/v1/token",
            data={
                "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
                "scope": "urn:opc:idm:__myscopes__",
                "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
            },
            headers={
                "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
            },
            auth=signer,
            timeout=30,
        )
        response.raise_for_status()

        token = response.json().get("access_token")
        if not isinstance(token, str) or not token:
            raise RuntimeError("Oracle IDCS did not return an access token.")

        return token

    return {"token_type": "jwt", "get_token": get_token}


client = OpenAI(
    workload_identity={
        "identity_provider_id": os.environ["OPENAI_IDENTITY_PROVIDER_ID"],
        "service_account_id": os.environ["OPENAI_SERVICE_ACCOUNT_ID"],
        "provider": oracle_instance_principal_token_provider(
            os.environ["OCI_IDENTITY_DOMAIN_URL"]
        ),
    },
)

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Say hello from Oracle Cloud Infrastructure workload identity federation.",
)

print(response.output_text)
```


The subject token provider requests a fresh Oracle token when the OpenAI SDK needs to renew the workload identity credential. Never print or persist the Oracle subject token or the resulting OpenAI access token.

## OCI security recommendations

- Map one instance with `ipst_instance` when only one workload should have access.
- Use `ipst_compartment` only when every eligible instance in that compartment should share the mapping.
- Add `domain_id` or `ca_ocid` to enforce identity domain and tenancy boundaries.
- Use a separate OpenAI service account for each application and environment.
- Verify whether an OKE token represents a worker node before relying on pod-level isolation.
- Use the audience present in the issued Oracle token rather than assuming an OpenAI-specific audience.
- Rotate uploaded public keys when Oracle rotates its signing keys if your identity domain cannot use OIDC discovery.