> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reducto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Oracle Cloud Infrastructure

> Call Reducto from Oracle Cloud Infrastructure with an instance principal token from your identity domain instead of a stored API key.

An Oracle Cloud Infrastructure (OCI) compute instance can sign a token request to an identity domain in its tenancy with its instance principal. The identity domain returns a signed access token. Reducto verifies that token and returns a Reducto access token.

There is no built-in OCI token provider in the Reducto SDKs. You pass a short function that uses the OCI SDK to get the token.

## Set up the instance

Run the workload on an OCI compute instance with an instance principal. The instance must reach the metadata service and, over HTTPS, its identity domain:

```bash theme={null}
curl --fail -sS -H "Authorization: Bearer Oracle" \
  http://169.254.169.254/opc/v2/instance/id
```

On Oracle Kubernetes Engine (OKE), the instance principal identifies the worker node, not the pod. Every pod on the node gets the same identity.

## Get and inspect a token

Sign a token exchange request to your identity domain with the instance principal:

```text theme={null}
POST https://<identity domain>/oauth2/v1/token
Content-Type: application/x-www-form-urlencoded

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 returned access token looks like this:

```json theme={null}
{
  "iss": "https://identity.oraclecloud.com/",
  "aud": [
    "https://idcs-4f2a8c1e9b3d4e7f.us-ashburn-1.identity.oraclecloud.com",
    "https://idcs-4f2a8c1e9b3d4e7f.identity.oraclecloud.com"
  ],
  "sub": "ocid1.instance.oc1.iad.anuwcljt3x7q2mexampleinstance",
  "sub_type": "instance",
  "ipst_instance": "ocid1.instance.oc1.iad.anuwcljt3x7q2mexampleinstance",
  "ipst_compartment": "ocid1.compartment.oc1..aaaaaaaa5kexamplecompartment",
  "domain_id": "ocid1.domain.oc1..aaaaaaaa7nexampledomain",
  "ca_ocid": "ocid1.tenancy.oc1..aaaaaaaa2bexampletenancy",
  "tenant": "idcs-4f2a8c1e9b3d4e7f",
  "iat": 1793322245,
  "exp": 1793325845
}
```

The audience comes from Oracle. You cannot request `https://platform.reducto.ai`, so configure Reducto with one of the `aud` values in your token. The `iss` is Oracle's global issuer, but the signing keys are published by your tenant's identity domain.

## Configure Reducto

In [Studio](https://studio.reducto.ai), open **Settings > Workload identity** and create a provider with the **Oracle Cloud** preset:

| Field | Value |
| - | - |
| **Name** | `oci-prod` |
| **Issuer** | `https://identity.oraclecloud.com/` |
| **Audience** | One `aud` value from your token, for example `https://idcs-4f2a8c1e9b3d4e7f.identity.oraclecloud.com` |
| **Key source** | **Custom discovery URL**: your identity domain, for example `https://idcs-4f2a8c1e9b3d4e7f.identity.oraclecloud.com` |

Reducto fetches `/.well-known/openid-configuration` from the identity domain and uses its `jwks_uri`. If Reducto cannot reach it, use **Uploaded JWKS** with the keys from `https://<identity domain>/admin/v1/SigningCert/jwk`, and update them when Oracle rotates its keys.

Add a mapping for the instance and tenancy:

| Key | Value |
| - | - |
| `ipst_instance` | `ocid1.instance.oc1.iad.anuwcljt3x7q2mexampleinstance` |
| `ca_ocid` | `ocid1.tenancy.oc1..aaaaaaaa2bexampletenancy` |

To allow every instance in a compartment, match `ipst_compartment` instead of `ipst_instance`.

These OCI claims are top-level claims, so the mapping matches them directly and the provider needs no attribute transformations.

## Call Reducto

Set `OCI_IDENTITY_DOMAIN_URL` to your identity domain, for example `https://idcs-4f2a8c1e9b3d4e7f.identity.oraclecloud.com`. The Python example needs `pip install reductoai oci requests`. The Node.js example needs `npm install reductoai oci-common`. The cURL example gets the Oracle token with the OCI Python SDK (`pip install oci requests`), because `oci raw-request` sends only JSON bodies and the identity domain token endpoint needs a form body.

```python Python theme={null}
import os

import oci
import requests
from reducto import Reducto

signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()


def oci_identity_token() -> str:
    response = requests.post(
        f"{os.environ['OCI_IDENTITY_DOMAIN_URL']}/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",
        },
        auth=signer,
        timeout=10,
    )
    response.raise_for_status()
    return response.json()["access_token"]


client = Reducto(
    workload_identity={
        "identity_provider_id": os.environ["REDUCTO_IDENTITY_PROVIDER_ID"],
        "provider": {"token_type": "jwt", "get_token": oci_identity_token},
    }
)

result = client.parse.run(input="https://cdn.reducto.ai/samples/fidelity-example.pdf")
print(result.result.chunks[0].content[:500])
```

```javascript Node.js theme={null}
import * as common from "oci-common";
import Reducto from "reductoai";

const authProvider =
  await new common.InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
const signer = new common.DefaultRequestSigner(authProvider);

async function ociIdentityToken() {
  const uri = `${process.env.OCI_IDENTITY_DOMAIN_URL}/oauth2/v1/token`;
  const body = new URLSearchParams({
    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",
  }).toString();
  const request = {
    uri,
    method: "POST",
    headers: new Headers({ "Content-Type": "application/x-www-form-urlencoded" }),
    body,
  };
  await signer.signHttpRequest(request);
  const response = await fetch(uri, { method: "POST", headers: request.headers, body });
  if (!response.ok) {
    throw new Error(`OCI token request failed: ${response.status}`);
  }
  return (await response.json()).access_token;
}

const client = new Reducto({
  workloadIdentity: {
    identityProviderId: process.env.REDUCTO_IDENTITY_PROVIDER_ID,
    provider: { tokenType: "jwt", getToken: ociIdentityToken },
  },
});

const result = await client.parse.run({
  input: "https://cdn.reducto.ai/samples/fidelity-example.pdf",
});
console.log(result.result.chunks[0].content.slice(0, 500));
```

```bash cURL theme={null}
SUBJECT_TOKEN=$(python3 - <<'PY'
import os

import oci
import requests

response = requests.post(
    f"{os.environ['OCI_IDENTITY_DOMAIN_URL']}/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",
    },
    auth=oci.auth.signers.InstancePrincipalsSecurityTokenSigner(),
    timeout=10,
)
response.raise_for_status()
print(response.json()["access_token"])
PY
)

ACCESS_TOKEN=$(jq -n \
  --arg subject_token "$SUBJECT_TOKEN" \
  --arg provider_id "$REDUCTO_IDENTITY_PROVIDER_ID" \
  '{
    grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
    subject_token_type: "urn:ietf:params:oauth:token-type:jwt",
    subject_token: $subject_token,
    identity_provider_id: $provider_id
  }' \
  | curl -sS --fail-with-body -X POST "https://platform.reducto.ai/oauth/token" \
      -H "Content-Type: application/json" -d @- \
  | jq -r .access_token)

curl -X POST "https://platform.reducto.ai/parse" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"input":"https://cdn.reducto.ai/samples/fidelity-example.pdf"}'
```

The SDK calls the function each time it needs a new access token. Do not print or store the Oracle token.

## OCI best practices

* Match `ipst_instance` when only one instance should have access. Match `ipst_compartment` only when every instance in the compartment should.
* Always add `ca_ocid` or `domain_id` to bind the mapping to your tenancy and identity domain.
* On OKE, remember that the instance principal is the node. Do not rely on it to separate pods.
* With an uploaded JWKS, update it when Oracle rotates the identity domain's signing keys.
