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

# Use Workload Identity with the SDKs

> Configure the Dodo Payments SDKs to exchange a platform OIDC token for a Dodo token and refresh it, or do the exchange yourself with curl.

Each Dodo Payments server SDK has a `workloadIdentity` client option. The SDK gets the JWT from your platform, does the exchange, keeps the Dodo token, and refreshes it.

> [!NOTE]
>
> The workload identity options are available from these SDK versions: TypeScript 2.58.0, Python 1.124.0, Go v1.124.0, Java 1.124.0, Kotlin 1.124.0, Ruby 2.36.0, PHP 6.33.0, C# 6.42.0, and Rust 1.125.0.

## Client Configuration

Give the SDK two values: the identity provider id (`wip_...`) and a provider helper that gets the JWT. The samples use live mode. The Java, Kotlin, and PHP clients use live mode when you do not set a mode.

```typescript TypeScript theme={null}
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  environment: 'live_mode',
  workloadIdentity: {
    identityProviderId: 'wip_...',
    provider: DodoPayments.workloadIdentity.githubActions(),
  },
});
```

```python Python theme={null}
from dodopayments import DodoPayments
from dodopayments.workload_identity import WorkloadIdentity, github_actions

client = DodoPayments(
    environment="live_mode",
    workload_identity=WorkloadIdentity(
        identity_provider_id="wip_...",
        provider=github_actions(),
    ),
)
```

```go Go theme={null}
import (
	"github.com/dodopayments/dodopayments-go"
	"github.com/dodopayments/dodopayments-go/option"
	"github.com/dodopayments/dodopayments-go/workloadidentity"
)

client := dodopayments.NewClient(
	option.WithEnvironmentLiveMode(),
	option.WithWorkloadIdentity(option.WorkloadIdentity{
		IdentityProviderID: "wip_...",
		Provider:           workloadidentity.GitHubActions(""),
	}),
)
```

```java Java theme={null}
import com.dodopayments.api.client.DodoPaymentsClient;
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient;
import com.dodopayments.api.workloadidentity.SubjectTokenProviders;
import com.dodopayments.api.workloadidentity.WorkloadIdentity;

DodoPaymentsClient client = DodoPaymentsOkHttpClient.builder()
    .workloadIdentity(WorkloadIdentity.builder()
        .identityProviderId("wip_...")
        .provider(SubjectTokenProviders.githubActions())
        .build())
    .build();
```

```kotlin Kotlin theme={null}
import com.dodopayments.api.client.DodoPaymentsClient
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient
import com.dodopayments.api.workloadidentity.SubjectTokenProviders
import com.dodopayments.api.workloadidentity.WorkloadIdentity

val client: DodoPaymentsClient = DodoPaymentsOkHttpClient.builder()
    .workloadIdentity(
        WorkloadIdentity.builder()
            .identityProviderId("wip_...")
            .provider(SubjectTokenProviders.githubActions())
            .build()
    )
    .build()
```

```ruby Ruby theme={null}
client = Dodopayments::Client.new(
  environment: "live_mode",
  workload_identity: Dodopayments::WorkloadIdentity::Config.new(
    identity_provider_id: "wip_...",
    provider: Dodopayments::WorkloadIdentity.github_actions
  )
)
```

```php PHP theme={null}
use Dodopayments\Client;
use Dodopayments\WorkloadIdentity\Providers;
use Dodopayments\WorkloadIdentity\WorkloadIdentity;

$client = new Client(
    workloadIdentity: new WorkloadIdentity(
        provider: Providers::githubActions(),
        identityProviderId: 'wip_...',
    ),
);
```

```csharp C# theme={null}
using DodoPayments.Client;
using DodoPayments.Client.Core;

DodoPaymentsClient client = new()
{
    BaseUrl = EnvironmentUrl.LiveMode,
    WorkloadIdentity = new()
    {
        IdentityProviderID = "wip_...",
        Provider = WorkloadIdentityProviders.GitHubActions(),
    },
};
```

```rust Rust theme={null}
use dodopayments::workload_identity;
use dodopayments::{Client, ClientConfig, WorkloadIdentity};

let client = Client::new(
    ClientConfig::new("https://live.dodopayments.com").with_workload_identity(
        WorkloadIdentity::new(workload_identity::github_actions(None))
            .with_identity_provider_id("wip_..."),
    ),
)?;
```

> [!WARNING]
>
> Do not set an API key (`bearerToken`) and `workloadIdentity` together. The SDK gives an error when you set the two options.

## Provider Helpers

Each SDK has the same set of helpers. The name follows the style of the language, for example `githubActions()` in TypeScript and `github_actions()` in Python.

| Helper | Use it for | How it gets the JWT |
| - | - | - |
| `githubActions()` | GitHub Actions | Requests a new token from the GitHub OIDC endpoint for each exchange. |
| `gitlab()` | GitLab CI/CD | Reads the ID token that your `.gitlab-ci.yml` defines. |
| `terraformCloud()` | HCP Terraform runs | Reads `TFC_WORKLOAD_IDENTITY_TOKEN`. |
| `gcp()` | Cloud Run, GCE, GKE | Requests an identity token from the metadata server. |
| `vercel()` | Vercel functions | Reads `VERCEL_OIDC_TOKEN`. This token has the default Vercel audience, which Dodo Payments does not accept. For a `vercel` provider, refer to the [Vercel guide](https://docs.dodopayments.com/developer-resources/workload-identity/providers/vercel.md#token-audience). |
| `kubernetes()` | Kubernetes and EKS | Reads the projected service account token file. |
| `file()` | Any platform that writes a JWT to a file | Reads the file in `DODO_PAYMENTS_IDENTITY_TOKEN_FILE`. |
| `aws(fn)` | AWS IAM outbound federation | Calls your function, which returns a JWT from AWS STS. |
| `static(token)` | Tests | Returns the JWT that you give. Java uses the name `staticToken(token)`, and Rust uses `static_token(token)`. |
| `auto()` | Code that runs on more than one platform | Finds the platform from the environment. |

The guide for each platform shows the configuration that the helper needs.

## Environment Variables

| Variable | Use |
| - | - |
| `DODO_PAYMENTS_IDENTITY_PROVIDER_ID` | The identity provider id. The SDK reads it when you do not set `identityProviderId`. If `DODO_PAYMENTS_API_KEY` is not set and this variable is set, the SDK uses workload identity with `auto()`. |
| `DODO_PAYMENTS_IDENTITY_TOKEN_FILE` | The path of a file that holds the JWT. The `file()` helper reads it. |

## Refresh and Retry

The SDK manages the Dodo token for you:

* It does the first exchange before the first API call.
* It does a new exchange when 5 minutes or less remain on the token.
* When many requests run at the same time, the SDK does one exchange for all of them.
* If an API call gets `401`, the SDK does one new exchange and tries the call one more time.

## Revoke the Token

To stop the current token before it expires, for example at the end of a CI job, call revoke:

```typescript TypeScript theme={null}
await client.workloadIdentity.revoke();
```

```python Python theme={null}
client.workload_identity.revoke()
```

```go Go theme={null}
err := client.WorkloadIdentity.Revoke(ctx)
```

```java Java theme={null}
client.workloadIdentity().revoke();
```

```kotlin Kotlin theme={null}
client.workloadIdentity()?.revoke()
```

```ruby Ruby theme={null}
client.workload_identity.revoke
```

```php PHP theme={null}
$client->workloadIdentity?->revoke();
```

```csharp C# theme={null}
await client.RevokeWorkloadIdentityToken();
```

```rust Rust theme={null}
client.revoke_workload_identity().await?;
```

```bash cURL theme={null}
curl -X POST https://live.dodopayments.com/workload-identity/token/revoke \
  -H "Authorization: Bearer $DODO_TOKEN"
```

The revoke call stops the cached token and clears the cache. The next API call does a new exchange.

## Raw HTTP Exchange

Without an SDK, send the JWT to `POST /workload-identity/token`. The request is an RFC 8693 token exchange and needs no API key. Use `https://test.dodopayments.com` for test mode.

```bash theme={null}
curl -X POST https://live.dodopayments.com/workload-identity/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
    "subject_token": "'"$PLATFORM_JWT"'",
    "identity_provider_id": "wip_..."
  }'
```

`subject_token_type` can also be `urn:ietf:params:oauth:token-type:id_token`.

A successful response:

```json theme={null}
{
  "access_token": "<dodo token>",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 3600,
  "expires_at": "2026-10-28T10:00:00Z",
  "scope": "<scope> <scope>"
}
```

Send `access_token` as `Authorization: Bearer <token>` on your API calls. There is no refresh token. Before `expires_at`, get a new JWT and do the exchange again.

An error response uses the OAuth 2.0 format:

```json theme={null}
{
  "error": "invalid_grant",
  "error_description": "<the claim or value to correct>"
}
```

Refer to [Exchange Errors](https://docs.dodopayments.com/developer-resources/workload-identity/overview.md#exchange-errors) for the error codes.

> **[GitHub Actions](https://docs.dodopayments.com/developer-resources/workload-identity/providers/github-actions.md)**
>
> Use workload identity in a GitHub Actions workflow.

> **[Kubernetes and EKS](https://docs.dodopayments.com/developer-resources/workload-identity/providers/kubernetes.md)**
>
> Use a projected service account token.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.