Workload Identity
Cloud providers issue OIDC tokens to workloads running in their environments. AWS assigns them to EKS pods via IRSA; GCP assigns them to any compute resource attached to a service account. These tokens are cryptographically signed by the provider and carry claims about the workload: which service account it runs as, which project or cluster it belongs to, and what it is authorized to do.
Descope can accept these tokens directly and issue a Descope access token in exchange, using the JWT-Bearer grant type. Your agent never needs a long-lived secret. It authenticates as a workload, gets a scoped Descope token, and uses that token to reach your APIs and MCP servers.
How It Works
- Your workload runs in AWS or GCP with a cloud identity attached (an IAM role or a GCP service account).
- It fetches an OIDC token from the cloud provider's metadata or token service.
- It presents that token to Descope's token endpoint using the JWT-Bearer grant.
- Descope validates the token against the configured trusted issuer, creates an agentic identity for the workload, and returns a Descope access token.
- The workload uses the Descope token to call your protected resources.
Prerequisites
Before you can exchange a workload token, create a client in Descope with the JWT-Bearer grant type enabled and configure your cloud provider as a trusted issuer.
- Go to Clients and create a new client, or open an existing one.
- Under Grant Types, enable JWT Bearer.
- Click Manage next to JWT Bearer and add a trusted issuer. The issuer URL and JWKs URL differ by provider — see the sections below.
- Save the client and copy the Client ID. You will pass this in the token request.
AWS
AWS EKS supports IAM Roles for Service Accounts (IRSA), which projects a signed OIDC token into each pod at a known path. Descope can validate these tokens against your cluster's OIDC issuer.
Trusted Issuer Configuration
Each EKS cluster has its own OIDC issuer URL. Find yours with:
aws eks describe-cluster \
--name YOUR_CLUSTER_NAME \
--query "cluster.identity.oidc.issuer" \
--output textThis returns a URL like https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLE1234.
In Descope, configure the trusted issuer with:
| Field | Value |
|---|---|
| Issuer URL | Your cluster's OIDC issuer URL |
| JWKs URL | {issuer_url}/keys (Descope derives this automatically if left blank) |
IRSA Setup
Annotate your Kubernetes service account with the IAM role ARN you want to associate with the workload:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-agent
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-agent-roleEKS projects a signed OIDC token into the pod at /var/run/secrets/eks.amazonaws.com/serviceaccount/token when you mount the volume in your pod spec:
volumes:
- name: aws-iam-token
projected:
sources:
- serviceAccountToken:
audience: YOUR_DESCOPE_CLIENT_ID
expirationSeconds: 3600
path: token
volumeMounts:
- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
name: aws-iam-tokenSet the audience field to your Descope client ID. Descope validates the aud claim on the incoming token.
Exchanging the Token
Read the projected token and exchange it at Descope's token endpoint:
import requests
with open("/var/run/secrets/eks.amazonaws.com/serviceaccount/token") as f:
workload_token = f.read().strip()
response = requests.post(
"https://api.descope.com/oauth2/v1/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": workload_token,
"client_id": "YOUR_DESCOPE_CLIENT_ID",
"scope": "openid",
},
)
descope_token = response.json()["access_token"]Use descope_token to call your protected APIs and MCP servers.
GCP
GCP assigns an OIDC identity to any compute resource that runs with a service account attached: Cloud Run services, GKE pods, Compute Engine VMs, and Cloud Functions. The token is available from the instance metadata server.
Trusted Issuer Configuration
GCP tokens are issued by Google's OAuth infrastructure. Configure the trusted issuer in Descope with:
| Field | Value |
|---|---|
| Issuer URL | https://accounts.google.com |
| JWKs URL | https://www.googleapis.com/oauth2/v3/certs |
Fetching the OIDC Token
The token comes from the metadata server. Set the audience query parameter to your Descope client ID:
curl -s \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=YOUR_DESCOPE_CLIENT_ID&format=full" \
-H "Metadata-Flavor: Google"From Python:
import requests
metadata_url = (
"http://metadata.google.internal/computeMetadata/v1/"
"instance/service-accounts/default/identity"
)
token_response = requests.get(
metadata_url,
params={"audience": "YOUR_DESCOPE_CLIENT_ID", "format": "full"},
headers={"Metadata-Flavor": "Google"},
)
workload_token = token_response.textRunning outside GCP
The metadata server is only reachable from inside a GCP compute environment. For local development, use a service account key file with the Google Auth Library to generate an equivalent OIDC token, or use a separate Descope client configured for development with client_credentials.
Exchanging the Token
response = requests.post(
"https://api.descope.com/oauth2/v1/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": workload_token,
"client_id": "YOUR_DESCOPE_CLIENT_ID",
"scope": "openid",
},
)
descope_token = response.json()["access_token"]GKE Workload Identity
For GKE, use Workload Identity Federation to bind a Kubernetes service account to a GCP service account. Once the binding is in place, pods fetch tokens the same way as any other GCP compute resource, via the metadata server.
Agentic Identity
Each time a workload exchanges a token, Descope creates or updates an agentic identity record for it. The identity carries the workload's claims as context — project, cluster, service account, and namespace — so you can write policies that target specific workloads and see per-workload audit trails in your logs.
For workloads sharing the same client ID but running in different environments (separate AWS accounts, separate GCP projects), each produces a distinct agentic identity. You can revoke one deployment's access without affecting others.