# Workload Identity Federation

Authenticate to the Stripe API without a long-lived API key.

Workload Identity Federation (WIF) lets your service or application authenticate to the Stripe API without a long-lived API key. Instead, you set up a trust relationship between Stripe and your cloud provider’s identity service (either AWS or Google Cloud in private preview). When your service runs, it obtains a short-lived identity token from your cloud provider, exchanges it with Stripe for an access token scoped to your service principal, and uses that access token to call the Stripe API.

## Request access  (Private preview)

Workload Identity Federation is in [private preview](https://docs.stripe.com/release-phases.md) and available to a limited number of users.

### Get early access to Workload Identity Federation

Enter your email to request access to the Workload Identity Federation private preview.

```bash
curl https://docs.stripe.com/preview/register \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Referer: https://docs.stripe.com/workload-identity-federation" \
  -d '{"email": "EMAIL", "preview": "wif_private_preview"}'
```

## How WIF differs from API key authentication 

API keys in Stripe have no default expiration. Anyone who obtains your key can use it until you rotate or expire it, so a leaked key creates a potentially long-lived security risk.

With WIF, you never manually create or copy an API key to your cloud provider, and your service never holds a long-lived secret. After configuring a trusted identity provider and creating a service principal in Stripe, Stripe’s SDK automatically exchanges your cloud provider’s identity token for a short-lived Stripe access token that expires in 1 hour. If the exchanged token leaks, the exposure is limited to its remaining lifetime.

| Authentication method | Credential lifetime | What your workload stores | Requests allowed from |
| --- | --- | --- | --- |
| **API keys** | No expiration | A static secret | Anywhere (including curl requests) |
| **Workload Identity Federation** | 1 hour | No static secrets | Anywhere, but tokens can only be issued to a trusted workload |

## Set up Workload Identity Federation 

## Before you begin

- Create a Stripe [organization](https://docs.stripe.com/get-started/account/orgs.md) with [private preview access](https://docs.stripe.com/workload-identity-federation.md#request-access) to WIF.
- Create an AWS account or Google Cloud project with permissions to create IAM roles or service accounts.
- Install the Stripe Ruby or TypeScript SDK (private-preview build).

## Set up your cloud identity provider

#### AWS

### Enable Outbound Identity Federation 

1. Open the [AWS Management Console](https://console.aws.amazon.com) and click **IAM**.
2. In the left menu, under Access management, select **Account settings**.
3. Find the **Outbound identity federation** section and select **Enable**.
4. Copy the **token issuer URL** that you see (**https://<uuid>.tokens.sts.global.api.aws**). You’ll need this in Stripe.

### Add the WIF policy to your workload’s IAM role 

Your workload’s IAM role is the identity that Stripe sees in the token exchange. Add the WIF permission policy to the role your workload already uses, then register that role’s ARN as the subject in Stripe.

If your workload already has a role (most production workloads do), find it:

- **Lambda**: Open the function, go to **Configuration** > **Permissions**, and click the execution role name.
- **EC2**: Select the instance, go to **Security**, and click the IAM role name.
- **ECS**: open the task definition and find the task role (not the task execution role, which ECS uses to pull images and write logs).

If your workload doesn’t have a role yet, or you’re testing locally, create one:

1. Go to **IAM** > **Roles** > **Create role**.
2. For **Trusted entity type**, choose **AWS service** for a workload or **AWS account** > **This account** for local testing.
3. Skip the “Add permissions” step and click **Next**.
4. Name the role (for example `stripe-caller`) and choose **Create role**.

Add the WIF policy to the role:

1. Open the role in IAM, go to the **Permissions** tab, and click **Add permissions** > **Create inline policy**.
2. Switch to the JSON editor and paste:

```json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "sts:GetWebIdentityToken",
    "Resource": "*",
    "Condition": {
      "ForAllValues:StringEquals": { "sts:IdentityTokenAudience": "https://access.stripe.com/wif" }
    }
  }]
}
```

1. Name the policy (for example `stripe-wif`) and save it.
2. Copy the role’s **ARN** from the top of the role page. This is the service principal’s subject in Stripe.

#### Google Cloud

Google Cloud uses the concept of service accounts, which maps to the concept of service principals in Stripe. By default, every Google service account can get Google-signed identity tokens, and the issuer URL is always **https://accounts.google.com**.

### Create a service account 

1. Open [console.cloud.google.com](https://console.cloud.google.com/) and select your project from the project picker at the top.
2. Go to **IAM & Admin** > **Service Accounts** and click **Create service account**.
3. Enter a name, such as `stripe-caller`. The ID and email fill in automatically.
4. Click **Create and continue**. Skip the “Grant this service account access to project” step, because calling Stripe needs no Google Cloud permissions, and click **Done**.
5. Open the new service account. On its **Details** tab, copy two values:
   - **Email**, such as `stripe-caller@<PROJECT_ID>.iam.gserviceaccount.com`.
   - **Unique ID**, a long number such as `104892101234567890123`. This becomes the token’s subject, or `sub`.

### Attach the service account to the workload 

- **Cloud Run**: go to the service, click **Edit & deploy new revision**, and select the service account under **Security**.
- **Compute Engine**: Stop the instance, click **Edit**, and select the service account under **Identity and API access**.
- **GKE**: Configure Workload Identity on the cluster and annotate the Kubernetes service account with `iam.gke.io/gcp-service-account=<SERVICE_ACCOUNT_EMAIL>`. Grant the Kubernetes service account the `roles/iam.workloadIdentityUser` role on the Google service account so it can obtain identity tokens:
  ```bash
  gcloud iam service-accounts add-iam-policy-binding <SERVICE_ACCOUNT_EMAIL> \
    --role=roles/iam.workloadIdentityUser \
    --member="serviceAccount:<PROJECT_ID>.svc.id.goog[<NAMESPACE>/<KSA_NAME>]"
  ```

## Create a service principal in Stripe

1. In the Stripe Dashboard, go to **Organization** > **Developers** > **API authentication** > [Service principals](https://dashboard.stripe.com/org/service-principals) and click **Create service principal**.
2. Select a trusted workload identity provider, or add a new one.
   - Enter the `Issuer URL` from your workload identity provider.
3. Name your service principal and paste the subject of your service from your cloud provider. The subject format table below clarifies the format per provider. You can add multiple subjects if your service principal is acting on behalf of multiple workloads.
4. After you create the service principal, copy its client ID `oacli_...`. You use this client ID when you exchange tokens in the next step.

| Provider | Subject format |
| --- | --- |
| AWS | The IAM role ARN your workload assumes, for example `arn:aws:iam::123456789012:role/my-workload-role` |
| Google Cloud | The numeric unique ID of the service account issuing the token |

## Authenticate requests to the Stripe API 

> During private preview, Workload Identity Federation is only supported using the Ruby and TypeScript SDKs.

The Stripe SDKs automatically handle the creation and exchange of short-lived access tokens for your workload to make calls to the Stripe API from your cloud provider. You only need to initialize the Stripe client and pass in the service principal’s client ID. Pass in the `stripeContext` to specify the account context for the request. Use `awsWorkloadIdentity()` for AWS or `gcpWorkloadIdentity()` for Google Cloud.

```typescript
import Stripe from "stripe";
import {awsWorkloadIdentity} from "@stripe/workload-identity"; // Use gcpWorkloadIdentity for Google Cloud

const stripe = Stripe.forWorkloadIdentity(
 'oacli_live_...',
 gcpWorkloadIdentity(),
);


const stripe = Stripe.forWorkloadIdentity(
  "oacli_...",
  awsWorkloadIdentity(), // Use gcpWorkloadIdentity() for Google Cloud
);

const customer = await stripe.customers.create(
  {
    name: "Jenny Rosen",
    email: "jenny@example.com",
  },
  {
    stripeContext: "acct_...",
  }
);
console.log(customer.id);
```

### Test your workload locally 

Test your integration to validate that the workload in your cloud provider can properly authenticate API requests in Stripe.

#### AWS

If you’re testing locally, use the AWS CLI to assume the role, then call the Stripe API from a local script. First, check who you are:

```bash
aws sts get-caller-identity
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
```

Next, create an AWS CLI profile so you can assume the role locally. Run these commands in the same terminal session as the previous step so that `ACCOUNT_ID` is set:

```bash
aws configure set role_arn "arn:aws:iam::${ACCOUNT_ID}:role/stripe-caller" --profile stripe-caller
aws configure set source_profile default --profile stripe-caller
aws configure set region us-east-1 --profile stripe-caller
```

Check that it works:

```bash
aws sts get-caller-identity --profile stripe-caller
```

The ARN in the output looks like the following: `arn:aws:sts::<ACCOUNT_ID>:assumed-role/stripe-caller/...`. That shows you’re acting as the role.

As a last step, set up the project and run the script with the stripe-caller profile so it authenticates as the role and not with your default credentials:

```bash
npm init -y
npm pkg set type=module
npm install stripe @stripe/workload-identity
AWS_PROFILE=stripe-caller npx tsx stripe_wif_create_customer.ts
```

#### Google Cloud

You can test directly from the Google Cloud Shell to call the Stripe API from an uploaded script. Grant your Google account permission to impersonate the service account.

1. In the [Google Cloud console](https://console.cloud.google.com/), go to **APIs & Services** > **Library**, search for **IAM Service Account Credentials API**, and click **Enable**. Impersonation won’t work without it.

2. Go to **IAM & Admin > Service Accounts** and open the service account. On the **Principals with access** tab, select **Grant access**.

3. Enter your Google account email and add two roles:

   - **Service Account OpenID Connect Identity Token Creator**: Lets you mint identity tokens as the service account.
   - **Service Account Token Creator**: Lets `gcloud auth application-default login` generate access tokens during impersonation.

   Click **Save**. Role changes can take 1 or 2 minutes to take effect.

Paste this into Cloud Shell, with your service account’s email in place of the placeholder:

```bash
SA=stripe-caller@<PROJECT_ID>.iam.gserviceaccount.com

JWT=$(gcloud auth print-identity-token \
  --impersonate-service-account=$SA \
  --audiences=https://access.stripe.com/wif --include-email)

echo "$JWT" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null; echo
```

The decoded output shows your service account’s email and a numeric sub. If you get a permission error, wait a minute for the role grant to take effect and try again.

Next, configure application default credentials so the Stripe SDK can obtain identity tokens as the service account:

```bash
gcloud auth application-default login --impersonate-service-account=$SA
```

Create a test script that uses `gcpWorkloadIdentity()`. To get the script into Google Cloud Shell, use the overflow menu (⋯) in the Cloud Shell toolbar and click **Upload**.

```typescript
import Stripe from "stripe";
import {gcpWorkloadIdentity} from "@stripe/workload-identity";

const stripe = Stripe.forWorkloadIdentity(
  "oacli_...",
  gcpWorkloadIdentity(),
);

const customer = await stripe.customers.create(
  {
    name: "Jenny Rosen",
    email: "jenny@example.com",
  },
  {
    stripeContext: "acct_...",
  }
);
console.log(customer.id);
```

Set up the project and run it:

```bash
npm init -y
npm pkg set type=module
npm install stripe @stripe/workload-identity
npx tsx stripe_wif_create_customer.ts
```

## See also

- [Service principals](https://docs.stripe.com/service-principals.md)
- [Best practices for API keys](https://docs.stripe.com/keys-best-practices.md)
