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.
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:
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:
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:
curl --fail https://api.example.com/dataYou 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 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. It identifies https://id.e2b.dev as the issuer and points to the JSON Web Key Set (JWKS), 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:
aws iam create-open-id-connect-provider \
--url https://id.e2b.dev \
--client-id-list sts.amazonaws.com \
--query OpenIDConnectProviderArn \
--output textFor 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:
{
"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:
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:
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 support to enable it for your BYOC deployment.
Get started with the workload identity documentation, including token verification and AWS federation setup. For the AWS exchange API, see AssumeRoleWithWebIdentity.
