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

  1. Your workload runs in AWS or GCP with a cloud identity attached (an IAM role or a GCP service account).
  2. It fetches an OIDC token from the cloud provider's metadata or token service.
  3. It presents that token to Descope's token endpoint using the JWT-Bearer grant.
  4. Descope validates the token against the configured trusted issuer, creates an agentic identity for the workload, and returns a Descope access token.
  5. 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.

  1. Go to Clients and create a new client, or open an existing one.
  2. Under Grant Types, enable JWT Bearer.
  3. Click Manage next to JWT Bearer and add a trusted issuer. The issuer URL and JWKs URL differ by provider — see the sections below.
  4. 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 text

This returns a URL like https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLE1234.

In Descope, configure the trusted issuer with:

FieldValue
Issuer URLYour 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-role

EKS 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-token

Set 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:

FieldValue
Issuer URLhttps://accounts.google.com
JWKs URLhttps://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.text

Running 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.

Was this helpful?

On this page