# Managed Auth with OpenID Connect — Connect Render services to popular providers using OIDC.

With a *Pro* workspace or higher, you can configure your Render services to authenticate with supported third-party providers using OpenID Connect (OIDC). Render manages a short-lived authentication token for each of your services that automatically rotates as needed.

Render currently supports managed OIDC for the following providers:

- AWS
- GCP
- Anthropic
- OpenAI

## Setup

> *Only an admin for your organization's provider account can complete these steps.*

Select the tab for your provider:

**Tab: AWS**

### AWS setup

#### 1. Add Render as an AWS Identity Provider

1. From your IAM Dashboard in the AWS Management Console, navigate to *Identity Providers*.
2. Add a new provider with the following settings:

    |  |  |
    | --- | --- |
    | *Provider Type* | `OpenID Connect` |
    | *Provider URL* | `oidc.render.com/{WORKSPACE_ID}` Replace `{WORKSPACE_ID}` with your workspace's ID, available from the top of its *Settings* page in the [Render Dashboard](https://dashboard.render.com) (starts with `tea-`). |
    | *Audience* | `sts.amazonaws.com` |

3. Click *Add provider*.

4. Copy the *ARN* for the newly created provider. You'll use this value when configuring trust relationships for AWS roles in the next step.

#### 2. Associate AWS roles with Render's OIDC identity

Do the following for _each_ AWS role you want to assign to your Render services:

1. From your IAM Dashboard in the AWS Management Console, navigate to *Roles*.
2. Create a new *Custom trust policy role* (or modify an existing one).
3. Under *Trust Relationship*, add the highlighted object to the `Statement` array, *substituting your provider ARN and workspace ID where indicated*:

    ```json
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Federated": "{PROVIDER_ARN}"
                },
                "Action": "sts:AssumeRoleWithWebIdentity",
                "Condition": {
                    "StringEquals": {
                        "oidc.render.com/{WORKSPACE_ID}:aud": "sts.amazonaws.com"
                    }
                }
            }
        ]
    }
    ```

After you've created and updated your roles, copy their *ARN* values. You'll use these values when assigning roles to individual Render services in the next section.

##### Scoping access to specific services

Optionally, you can add finer-grained validation on the OIDC subject by checking the `oidc.render.com/{WORKSPACE_ID}:sub` value, which has the following format:

```
workspace:{WORKSPACE_ID}:environment:{ENVIRONMENT_ID}:service:{SERVICE_ID}
```

You can include multiple wildcards in your validation string with a `StringLike` condition.

For details, see [Scoping access](#scoping-access).

#### 3. Connect individual services

Do the following for _each_ service you want to connect:

1. Add an environment variable named `AWS_ROLE_ARN` to your service. Set its value to the *ARN* of the role you want to assign to the service.
    - You can assign only one role per service.
2. Redeploy the service with the new environment variable.

During the deploy, Render detects the new environment variable and automatically sets an _additional_ environment variable named `AWS_WEB_IDENTITY_TOKEN_FILE` to the file path of your service's OIDC credentials.

> *Do not manually set the `AWS_WEB_IDENTITY_TOKEN_FILE` environment variable.*
>
> If you do, it might not match the credentials Render automatically sets.

**Tab: Google Cloud**

### GCP setup

#### 1. Add Render as a workload identity pool provider

1. In the [Google Cloud console](https://console.cloud.google.com), select your project and enable the [following APIs](https://console.cloud.google.com/apis/library):

    - Identity and Access Management (IAM) API
    - Security Token Service API
    - IAM Service Account Credentials API (required for [service account impersonation](#option-b-grant-roles-to-a-service-account))

    Alternatively, run the following command with the `gcloud` CLI to enable these APIs:

    ```shell
    gcloud services enable iam.googleapis.com sts.googleapis.com iamcredentials.googleapis.com
    ```

2. From the Google Cloud console, navigate to *IAM & Admin > Workload Identity Federation*.
3. Create a new workload identity pool (or select an existing one).
4. Add a provider to the pool with the following settings:

    |  |  |
    | --- | --- |
    | *Provider type* | `OpenID Connect (OIDC)` |
    | *Issuer (URL)* | `https://oidc.render.com/{WORKSPACE_ID}` Replace `{WORKSPACE_ID}` with your workspace's ID (starts with `tea-`), available from the top of its *Settings* page in the [Render Dashboard](https://dashboard.render.com). |
    | *Audiences* | `Default audience` |
    | *Attribute mapping* | `google.subject` = `assertion.sub` |

    Alternatively, run the following command with the `gcloud` CLI to create the pool and provider:

    ```shell
    gcloud iam workload-identity-pools create {POOL_ID} --location=global && \
    gcloud iam workload-identity-pools providers create-oidc {PROVIDER_ID} \
      --location=global \
      --workload-identity-pool={POOL_ID} \
      --issuer-uri="https://oidc.render.com/{WORKSPACE_ID}" \
      --attribute-mapping="google.subject=assertion.sub"
    ```

    Replace `{POOL_ID}` and `{PROVIDER_ID}` with names of your choosing, and `{WORKSPACE_ID}` with your workspace's ID.

5. Optionally, add an [*attribute condition*](https://docs.cloud.google.com/iam/docs/workload-identity-federation#conditions) to restrict which Render services can authenticate to GCP. If you do not [grant access to individual services](#2-grant-access-to-google-cloud-resources) in the next step, we recommend adding an attribute condition to allowlist specific services.

    An attribute condition is a CEL expression that matches against the OIDC subject (`assertion.sub`). For example, to allow only services in the `evm-def456` environment:

    ```
    assertion.sub.startsWith("workspace:tea-abc123:environment:evm-def456:")
    ```

    For details, see [Scoping access](#scoping-access).

6. In a following step, you'll need your provider's resource name, which uses the following format:

    ```
    projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/providers/{PROVIDER_ID}
    ```

    - Your *project number* (not the project ID) is available from the Google console's *IAM & Admin > Settings* page.
    - Your *pool ID* and *provider ID* are available from your pool and provider pages, respectively.

    Alternatively, run the following command with the `gcloud` CLI to print the resource name:

    ```shell
    gcloud iam workload-identity-pools providers describe {PROVIDER_ID} \
      --location=global \
      --workload-identity-pool={POOL_ID} \
      --format="value(name)"
    ```

    Replace `{POOL_ID}` and `{PROVIDER_ID}` with the names of your pool and provider.

#### 2. Grant access to Google Cloud resources

Render services are represented by [federated principals](https://docs.cloud.google.com/iam/docs/principals-overview) when they authenticate to GCP. Granting IAM roles to those principals lets your services access your Google Cloud resources.

To grant a role to a _specific_ Render service, you'll use the following principal:

```
principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/subject/workspace:{WORKSPACE_ID}:environment:{ENVIRONMENT_ID}:service:{SERVICE_ID}
```

To grant a role to _every_ identity in your pool, you'll use the following principal set instead:

```
principalSet://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/*
```

This principal set grants access to _every_ service in your workspace unless you added an attribute condition to allowlist specific services in the [previous step](#1-add-render-as-a-workload-identity-pool-provider).

##### Option A: Grant roles to a federated principal (recommended)

Most Google Cloud APIs support direct access from federated principals. To access these APIs, grant a role directly to the principal:

1. In the Google Cloud console, navigate to *IAM & Admin > IAM*.
    - To grant access to a single resource instead of the whole project, open that resource's permissions (for example, the *Permissions* tab of a Cloud Storage bucket).
2. Click *Grant access*.
3. Under *New principals*, paste the principal (or principal set) [from above](#2-grant-access-to-google-cloud-resources), replacing the placeholders with your own values.
4. Select the roles you want to grant, then click *Save*.

Alternatively, run the following command with the `gcloud` CLI to grant a role to the principal:

```shell
gcloud projects add-iam-policy-binding {PROJECT_ID} \
  --member="principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/subject/workspace:{WORKSPACE_ID}:environment:{ENVIRONMENT_ID}:service:{SERVICE_ID}" \
  --role="{ROLE}"
```

##### Option B: Grant roles to a service account

For Google Cloud APIs that don't support federated principals, have your Render service impersonate a service account and grant it the roles instead:

1. In the Google Cloud console, navigate to *IAM & Admin > Service Accounts*.
2. Select an existing service account, or create a new one.
3. Open the service account's *Principals with access* tab, then click *Grant access*.
4. Under *New principals*, paste the principal (or principal set) [from above](#2-grant-access-to-google-cloud-resources), replacing the placeholders with your own values.
5. Select the *Workload Identity User* role (`roles/iam.workloadIdentityUser`), then click *Save*.
6. Grant the _service account_ the roles it needs, as described in [Option A](#option-a-grant-roles-to-a-federated-principal-recommended), using the service account's email address as the principal.

Alternatively, run the following command with the `gcloud` CLI to grant the *Workload Identity User* role:

```shell
gcloud iam service-accounts add-iam-policy-binding {SERVICE_ACCOUNT_EMAIL} \
  --member="principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/subject/workspace:{WORKSPACE_ID}:environment:{ENVIRONMENT_ID}:service:{SERVICE_ID}" \
  --role="roles/iam.workloadIdentityUser"
```

#### 3. Connect individual services

Set the following environment variables on each service you want to connect to GCP, then redeploy:

| Variable | Description |
| --- | --- |
| `GCP_WORKLOAD_IDENTITY_PROVIDER` | *Required.* The resource name of the [provider you created](#1-add-render-as-a-workload-identity-pool-provider) (starts with `projects/`). You can also paste the provider's full URL (starting with `https://iam.googleapis.com/`). |
| `GCP_SERVICE_ACCOUNT_EMAIL` | *Optional.* If you're using a [service account](#option-b-grant-roles-to-a-service-account), specify the email address of the service account to impersonate. |

During the deploy, Render detects `GCP_WORKLOAD_IDENTITY_PROVIDER` and writes a [credential configuration file](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create-cred-config) for your service's OIDC token. Render then sets an _additional_ environment variable, `GOOGLE_APPLICATION_CREDENTIALS`, to the path of the new file.

> *Do not manually set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.*
>
> If you do, it might not match the credentials Render automatically sets.

Google Cloud client libraries use `GOOGLE_APPLICATION_CREDENTIALS` automatically through [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials):

**Subtab: TypeScript**

```typescript
import { Storage } from "@google-cloud/storage";

const storage = new Storage({ projectId: "my-project" });

const [buckets] = await storage.getBuckets();
for (const bucket of buckets) {
    console.log(bucket.name);
}
```

**Subtab: Python**

```python
from google.cloud import storage

client = storage.Client(project="my-project")

for bucket in client.list_buckets():
    print(bucket.name)
```

The client libraries in the examples above request their OAuth scopes automatically.

If you use a general-purpose library (such as `google-auth` or `google-api-python-client`), you must _also_ specify a scope when authenticating:

```python
import google.auth

credentials, project = google.auth.default(
    scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
```

The `cloud-platform` scope grants access to all Google Cloud APIs.

To authenticate the `gcloud` CLI on a service (for example, over [SSH](ssh)), you can use the credential file Render created:

```shell
gcloud auth login --cred-file="$GOOGLE_APPLICATION_CREDENTIALS"
```

**Tab: Anthropic**

### Anthropic setup

#### 1. Create an Anthropic service account

1. In the Claude Console, open your organization's [Service accounts page](https://platform.claude.com/settings/service-accounts).
2. Create a new service account with the *Developer* role to use for your OIDC connection.

#### 2. Add Render as an Anthropic Identity Provider

1. Still in the Claude Console, navigate to your organization's [Workload identity federation page](https://platform.claude.com/settings/workload-identity-federation) and select the *Issuers* tab.

2. Connect a new Custom OIDC provider with the following settings:

    |  |  |
    | --- | --- |
    | *Issuer URL* | `https://oidc.render.com/{WORKSPACE_ID}` Replace `{WORKSPACE_ID}` with your workspace's ID (starts with `tea-`), available from the top of its *Settings* page in the [Render Dashboard](https://dashboard.render.com). |
    | *JWKS source* | OIDC Discovery |

#### 3. Create a federation rule

1. Still on the [Workload identity federation page](https://platform.claude.com/settings/workload-identity-federation), switch to the *Rules* tab.
2. Create a new federation rule with the following settings:

    |  |  |
    | --- | --- |
    | *Subject pattern* | This value specifies _which_ services in your workspace can authenticate via this rule. Provide a value in the format described in [Scoping access](#scoping-access). For example: ```
    workspace:tea-abc123:environment:evm-def456:service:*
    ``` This example matches all services in the `evm-def456` environment. |
    | *Expected audience* | `api.anthropic.com` |
    | *Token lifetime* | At least 30 minutes |

#### 4. Connect your Render service

Set the following environment variables on your service, then redeploy:

- `ANTHROPIC_FEDERATION_RULE_ID` - The ID of the federation rule you created in the previous step.
- `ANTHROPIC_ORGANIZATION_ID` - The ID of your Anthropic organization, which is available from the [Anthropic Organization tab](https://platform.claude.com/settings/organization).
- `ANTHROPIC_SERVICE_ACCOUNT_ID` - The ID of the service account you connected earlier, which is available from the [Anthropic Service account tab](https://platform.claude.com/settings/service-accounts).
- `ANTHROPIC_WORKSPACE_ID` - The ID of your Anthropic workspace, which is available from the [Anthropic Workspaces tab](https://platform.claude.com/settings/workspaces).

During the deploy, Render detects the `ANTHROPIC_FEDERATION_RULE_ID` environment variable and automatically sets an _additional_ environment variable named `ANTHROPIC_IDENTITY_TOKEN_FILE` to the file path of your service's OIDC credentials.

> *Do not manually set the `ANTHROPIC_IDENTITY_TOKEN_FILE` environment variable.*
>
> If you do, it might not match the credentials Render automatically sets.

By reading the environment variables above, the Anthropic SDK can authenticate automatically:

**Subtab: TypeScript**

```typescript
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

const message = await client.messages.create({
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }],
    model: "claude-sonnet-5"
});

for (const block of message.content) {
    if (block.type === "text") {
        console.log(block.text);
    }
}
```

**Subtab: Python**

```python
from anthropic import Anthropic

client = Anthropic()

message = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(message.content[0].text)
```

#### 5. Test your connection (optional)

To test your connection with Anthropic:

1. Navigate to the *Test connection* tab of the OIDC rule you set up earlier.
2. [SSH into your service](ssh) and run the provided test script, setting `JWT=$(cat $ANTHROPIC_IDENTITY_TOKEN_FILE)`.

**Tab: OpenAI**

### OpenAI setup

#### 1. Add Render as an OpenAI Identity Provider

1. From your [Organization settings](https://platform.openai.com/settings/organization/security/workload-identity-provider), navigate to the *Security* section, then to the *Workload Identity Provider* tab.
2. Create a new identity provider with the following settings:

    |  |  |
    | --- | --- |
    | *OIDC Issuer URL* | `https://oidc.render.com/{WORKSPACE_ID}` Replace `{WORKSPACE_ID}` with your workspace's ID (starts with `tea-`), available from the top of its *Settings* page in the [Render Dashboard](https://dashboard.render.com). |
    | *Audience* | `api.openai.com` |

#### 2. Create a service mapping

1. Select the newly created identity provider, then create a new mapping.
2. Set the following value:

    ------

    ##### sub

    This value specifies _which_ services in your workspace can authenticate via this mapping. Provide a value in the format described in [Scoping access](#scoping-access).

    For example:

    ```
    workspace:tea-abc123:environment:evm-def456:service:*
    ```

    This example matches all services in the `evm-def456` environment.

    ------

3. Choose or create a service account for your Render service to use. You will need the User ID of this account later, so after creating the mapping visit the [People tab](https://platform.openai.com/settings/organization/people/members), select the service account, and copy the User ID visible in the details panel.

#### 3. Connect your Render service

1. Set the following environment variables on your service, then redeploy:

    - `OPENAI_IDENTITY_PROVIDER_ID` - The identity provider ID from your OpenAI setup.
    - `OPENAI_SERVICE_ACCOUNT_ID` - The ID of the service account from your OpenAI setup, available in the [OpenAI People tab](https://platform.openai.com/settings/organization/people/members).

    During the deploy, Render detects the `OPENAI_IDENTITY_PROVIDER_ID` environment variable and automatically sets an _additional_ environment variable named `OPENAI_IDENTITY_TOKEN_FILE` to the file path of your service's OIDC credentials.

> *Do not manually set the `OPENAI_IDENTITY_TOKEN_FILE` environment variable.*
>
>     If you do, it might not match the credentials Render automatically sets.

2. Your code should read the token from this file path at runtime and use it to initialize the OpenAI client:

    **Subtab: TypeScript**

    ```typescript
    import { readFileSync } from "node:fs";
    import OpenAI from "openai";

    const tokenPath = process.env.OPENAI_IDENTITY_TOKEN_FILE!;

    const client = new OpenAI({
      workloadIdentity: {
        identityProviderId: process.env.OPENAI_IDENTITY_PROVIDER_ID!,
        serviceAccountId: process.env.OPENAI_SERVICE_ACCOUNT_ID!,
        provider: {
          tokenType: "jwt",
          getToken: () => readFileSync(tokenPath, "utf8").trim(),
        },
      },
    });
    ```

    **Subtab: Python**

    ```python
    import os
    from pathlib import Path

    from openai import OpenAI

    TOKEN_PATH = os.environ.get("OPENAI_IDENTITY_TOKEN_FILE")

    client = OpenAI(
        workload_identity={
            "identity_provider_id": os.environ["OPENAI_IDENTITY_PROVIDER_ID"],
            "service_account_id": os.environ["OPENAI_SERVICE_ACCOUNT_ID"],
            "provider": {
                "token_type": "jwt",
                "get_token": Path(TOKEN_PATH).read_text().strip
            },
        },
    )
    ```

## Scoping access

Each Render service's OIDC token contains a subject (`sub`) claim that identifies exactly which service is requesting access. This claim's value always has the following format:

```
workspace:{WORKSPACE_ID}:environment:{ENVIRONMENT_ID}:service:{SERVICE_ID}
```

| Component | Description |
| --- | --- |
| `{WORKSPACE_ID}` | Your Render workspace ID, which starts with `tea-`. You can find this value at the top of the workspace's *Settings* page in the [Render Dashboard](https://dashboard.render.com). |
| `{ENVIRONMENT_ID}` | An environment ID, which starts with `evm-`. You can find this value in the URL of the environment's *Settings* page in the [Render Dashboard](https://dashboard.render.com). For services that do not belong to an environment, this value is `default`. |
| `{SERVICE_ID}` | The service ID, which starts with `srv-`. You can find this value at the top of the service's *Settings* page in the [Render Dashboard](https://dashboard.render.com). |

Use this value when configuring your provider’s access rules. You can use an exact subject to authorize a single service, or use wildcard matching where supported by your provider.

Here are some example validation strings compatible with all supported providers:

```python
# Allow all services in workspace tea-abc123
workspace:tea-abc123:*

# Allow all services in environment evm-def456
workspace:tea-abc123:environment:evm-def456:*

# Only allow the single service srv-ghi789
workspace:tea-abc123:environment:evm-def456:service:srv-ghi789
```

## Limitations

- Currently, OIDC auth is not available at build time for services that build [from a Dockerfile](docker#building-from-a-dockerfile).
  - OIDC _is_ available at build time for services on any [native runtime](native-runtimes).
- OIDC auth does not currently enable [image-backed services](/deploying-an-image) to pull private images from AWS ECR.
  - These services _can_ pull private images from AWS ECR using a [generated credential](/deploying-an-image#credentials-for-private-images).

## Troubleshooting

###### "No OpenIDConnect provider found in your account for https://oidc.render.com/WORKSPACE_ID"

The AWS identity provider configuration for Render was not set up correctly. Make sure that your *Provider URL* matches the URL in the error message.

###### Google Cloud returns an invalid audience error

Make sure `GCP_WORKLOAD_IDENTITY_PROVIDER` is your provider's full resource name, in the following format:

```
projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{POOL_ID}/providers/{PROVIDER_ID}
```

Use your project _number_, not your project ID. Also make sure your provider's *Audiences* setting is `Default audience`.

###### Google Cloud returns "Scope(s) must be provided"

Google Cloud requires each client to specify an access scope when it authenticates with OIDC. Request the `cloud-platform` scope when you load credentials. For example, in Python:

```python
credentials, project = google.auth.default(
    scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
```


---

##### Appendix: Glossary definitions

###### environment variable

Config values you can apply to a service to customize its behavior at build and runtime, such as `NODE_VERSION` or `OPENAI_API_KEY`.

Render sets some environment variables for your service by [default](environment-variables).

Related article: https://render.com/docs/configure-environment-variables.md