---
title: Introducing E2B Workload Identity
description: "Give each sandbox a signed identity so your backend can verify who is calling and decide what it can access, without distributing long-lived credentials."
date: 2026-11-03
author: giulio-micheloni
categories:
  - product
thumbnail: "./thumbnail.png"
thumbnailAlt: E2B Workload Identity with an Authorization header and an orange token bar on a black background
---

Who is calling you? Your sandbox needs to fetch a document from your backend, submit the result of a task, or call an internal service. Before serving that request, your backend needs to know who is asking and what they should be allowed to do.

A shared API key can authenticate the request, but it doesn’t identify which sandbox sent it. You could issue a separate credential for every sandbox, then build the machinery to distribute, rotate, and track those credentials.

We built **E2B Workload Identity** to make this easier. E2B supplies a signed JSON Web Token (JWT) identifying the project, sandbox, and execution behind a request. Your service can verify that identity and apply its own access rules.

For us, this is another part of making sandboxes useful for real applications. Your agents need access to your systems, and your systems need a reliable way to identify them.

## How it works

When creating a sandbox, you define a named workload token and its audience, that is, the service you intend to receive it. Then you reference that token in a network rule.

When a matching HTTPS request leaves the sandbox, E2B adds a signed token to the request header you configured. E2B handles token issuance outside the sandbox, keeping the token out of the sandbox’s environment and filesystem.

<Image theme="dark" src="./image-diagram.png" alt="A sandbox sends an HTTPS request without a workload token. E2B adds a signed JWT outside the sandbox, and the receiving service verifies its identity and permissions using E2B's public keys." width={1690} height={931} />

<Image theme="light" src="./image-diagram-light.png" alt="A sandbox sends an HTTPS request without a workload token. E2B adds a signed JWT outside the sandbox, and the receiving service verifies its identity and permissions using E2B's public keys." width={3200} height={1760} />

The token carries an expiration and the intended audience. Your service verifies those claims alongside the signature and caller identity before accepting the request.

## Connect your sandbox to your backend

Suppose your sandbox needs to call `api.example.com`. First, define the workload token reference:

```typescript
import { Secret } from 'e2b'

const backendToken = Secret.iamToken({
  audience: 'api.example.com',
  tokenType: 'JWT-SVID',
})
```

This defines the token’s audience and type. The signed JWT is supplied by E2B when forwarding matching requests.

Then use that reference when creating the sandbox and configure the header that will carry the token:

```typescript
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create({
  iam: {
    tokens: {
      backend: backendToken,
    },
  },
  network: {
    allowOut: ({ rules }) => [...rules.keys()],
    denyOut: ({ allTraffic }) => [allTraffic],
    rules: {
      'api.example.com': [{
        transform: ({ iam }) => ({
          headers: {
            Authorization: `Bearer ${iam.tokens.backend}`,
          },
        }),
      }],
    },
  },
})
```

`iam.tokens.backend` is a reference, not the JWT itself. E2B substitutes the token outside the sandbox when forwarding matching requests. It can reuse a cached token for the same sandbox execution and audience while the token is valid. You can choose any HTTP request header your service expects.

Inside the sandbox, your code makes a normal HTTPS request:

```bash
curl --fail https://api.example.com/data
```

You don’t need to send an `Authorization` header, even with a dummy value. E2B creates the configured header after the request leaves the sandbox.

If your HTTP client uses its own CA bundle, configure it to trust E2B’s egress proxy. See [TLS certificates](https://docs.e2b.dev/network/internet-access#tls-certificates) for Python Requests and Node.js settings.

## Let your service decide what the sandbox can do

For E2B Cloud, E2B publishes an [OpenID Connect (OIDC) discovery document](https://id.e2b.dev/.well-known/openid-configuration). It identifies `https://id.e2b.dev` as the issuer and points to the [JSON Web Key Set (JWKS)](https://id.e2b.dev/.well-known/jwks.json), which contains E2B’s public signing keys. BYOC deployments use their own issuer URL and public keys, configured when support enables Workload Identity for the deployment.

Your backend can use a JWT verification library to fetch and cache those keys. The library selects the matching key using the token’s `kid` header and verifies the signature. Configure it to accept ES256 signatures, require the expected issuer and audience, and check the expiration and not-before times. Also check that the token’s subject belongs to your project and the sandbox execution you expect.

Your application then connects that identity to its own permissions.

For example, when starting a document-processing task, your backend can associate the sandbox ID with that task. When the sandbox requests a document, your backend checks that association before returning the data. The same approach can let a sandbox submit results for its assigned job or call a specific internal tool.

E2B provides the signed workload identity. You decide which resources and operations that identity can access.

## Access AWS resources with temporary credentials

Suppose your sandbox needs to read an object from an S3 bucket. Your backend can receive the injected E2B JWT, exchange it with AWS Security Token Service (STS), and use the temporary credentials to fetch the document.

For this example, set `audience: 'sts.amazonaws.com'` in the `backendToken` definition above. Keep the network rule pointing to your backend at `api.example.com`.

First, register E2B as an OpenID Connect (OIDC) provider in the AWS account that owns your role. For E2B Cloud, run:

```bash
aws iam create-open-id-connect-provider \
  --url https://id.e2b.dev \
  --client-id-list sts.amazonaws.com \
  --query OpenIDConnectProviderArn \
  --output text
```

For BYOC, replace `https://id.e2b.dev` with the issuer URL provided when support enables Workload Identity for your deployment. Register each issuer once per AWS account. If it already exists, reuse that provider and ensure its audience list includes `sts.amazonaws.com`.

The provider registration alone doesn’t restrict access to your E2B project. Save this role trust policy as `trust-policy.json`, replacing `123456789012` with your AWS account ID and `<PROJECT_ID>` with your E2B project ID:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/id.e2b.dev"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "id.e2b.dev:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "id.e2b.dev:sub": "spiffe://id.e2b.dev/<PROJECT_ID>/*"
        }
      }
    }
  ]
}
```

For BYOC, use your deployment’s issuer host in the provider ARN and condition keys. In the `spiffe://` subject, use the deployment’s configured trust domain, which can differ from the issuer host. Support can provide both values.

Create the role and grant access to the single S3 object used below, replacing the example bucket and object path with your own:

```bash
aws iam create-role \
  --role-name e2b-document-reader \
  --assume-role-policy-document file://trust-policy.json

aws iam put-role-policy \
  --role-name e2b-document-reader \
  --policy-name read-document \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-private-documents/documents/brief.txt"
    }]
  }'
```

Install `flask` and `boto3` in your Python 3 environment. Save this example as `app.py`, replacing the role ARN, bucket name, and region with your own:

```python
import boto3
from botocore import UNSIGNED
from botocore.config import Config
from botocore.exceptions import BotoCoreError, ClientError
from flask import Flask, Response, abort, request

app = Flask(__name__)
sts = boto3.client("sts", region_name="us-east-1", config=Config(signature_version=UNSIGNED))

@app.get("/data")
def get_document():
    auth = request.authorization
    if not auth or auth.type != "bearer" or not auth.token:
        abort(401)

    try:
        credentials = sts.assume_role_with_web_identity(
            RoleArn="arn:aws:iam::123456789012:role/e2b-document-reader",
            RoleSessionName="sandbox",
            WebIdentityToken=auth.token,
            DurationSeconds=900,
        )["Credentials"]
        s3 = boto3.client(
            "s3",
            region_name="us-east-1",
            aws_access_key_id=credentials["AccessKeyId"],
            aws_secret_access_key=credentials["SecretAccessKey"],
            aws_session_token=credentials["SessionToken"],
        )
        with s3.get_object(
            Bucket="my-private-documents", Key="documents/brief.txt"
        )["Body"] as document:
            return Response(document.read(), mimetype="text/plain")
    except (BotoCoreError, ClientError):
        abort(502, description="Could not retrieve document")
```

The STS call uses the workload token for authentication. `UNSIGNED` tells Boto3 not to look for AWS access keys for that call.

For a local preview, run `flask --app app run --port 3000`. When connecting your sandbox, deploy the endpoint behind HTTPS at `https://api.example.com/data`.

The sandbox calls the same `curl --fail https://api.example.com/data` command shown above. E2B adds the JWT to the request. STS validates it against the configured identity provider and role trust policy before returning temporary credentials. The backend uses those credentials to read S3 and returns only the document to the sandbox.

This example allows every identity accepted by the role’s trust policy to read the same document. For documents assigned to individual sandbox jobs, also check the verified identity against the job’s permissions.

The AWS credentials expire after 15 minutes in this example, independently of the E2B token. No long-lived AWS access keys are needed for the exchange.

## Get started

E2B Workload Identity is now generally available on E2B Cloud. It is also supported in Bring Your Own Cloud (BYOC) deployments. Contact <Link href="mailto:support@e2b.dev" data-cta-id="resource_workload_identity_support">support</Link> to enable it for your BYOC deployment.

Get started with the [workload identity documentation](https://docs.e2b.dev/iam/workload-identity), including token verification and AWS federation setup. For the AWS exchange API, see [AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html).
