OIDC with Depot CI
Depot CI supports OpenID Connect (OIDC) so your workflows can authenticate with cloud providers like AWS, GCP, and Azure using short-lived tokens instead of static credentials.
How it works
OIDC (OpenID Connect) is a standard for token-based authentication. Instead of storing long-lived credentials like API keys or passwords in your CI, your job receives a short-lived signed token that proves its identity. Your cloud provider verifies the token against Depot CI's public endpoint and grants access based on the claims inside it.
Depot CI automatically issues a signed JSON Web Token (JWT) to each job.
To use OIDC with Depot CI you'll need to configure a trust relationship between Depot CI and your cloud provider, then request the token in your workflows and use it to authenticate.
The Depot CI OIDC token
Each job in Depot CI receives a JWT. You must set permissions: id-token: write in your workflow YAML for the token to be issued.
The following is an example token for a GitHub repository:
{
"actor": "my-username",
"actor_id": "1000000",
"aud": ["sts.amazonaws.com"],
"base_ref": "",
"event_name": "push",
"exp": 1773766359,
"forge": "github",
"head_ref": "",
"iat": 1773766059,
"iss": "https://identity.depot.dev",
"job_id": "job_xxxxxxxxxxxx",
"org_id": "xxxxxxxxxxxxxxxxxxxx",
"ref": "refs/heads/main",
"ref_type": "branch",
"repository": "my-org/my-repo",
"repository_id": "123456789",
"repository_owner": "my-org",
"repository_owner_id": "12345678",
"repository_visibility": "private",
"run_attempt": "1",
"run_id": "run_xxxxxxxxxxxx",
"run_number": "42",
"sha": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"sub": "spiffe://identity.depot.dev/org/xxxxxxxxxxxxxxxxxxxx/ci/github/my-org/my-repo/ref/refs/heads/main/sandbox/snd_xxxxxxxxxxxx",
"workflow": "ci.yaml",
"workflow_ref": "my-org/my-repo/ci.yaml@refs/heads/main",
"workflow_sha": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}Use your Depot organization ID exactly as shown in Depot when matching the org_id claim. Don't add an org_ prefix. The sub claim uses the same ID after the literal /org/ path segment.
Restrict trust policies with the subject claim
The sub claim is how you restrict a trust policy to a specific org, repository, or branch. It reads left to right, from the most stable identifier to the most ephemeral. The ci/<forge> segment names the forge that hosts the repository. The full claim has one of the following formats:
| Forge | sub format |
|---|---|
| GitHub | spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID> |
| Entire | spiffe://identity.depot.dev/org/<orgID>/ci/entire/<namespace>/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID> |
| Cursor Origin | spiffe://identity.depot.dev/org/<orgID>/ci/origin/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID> |
| Depot Code | spiffe://identity.depot.dev/org/<orgID>/ci/code/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID> |
The ci/origin form applies only to Origin-hosted repositories. For these, <owner>/<repo> is the Origin namespace and repository name. GitHub triggers runs for an Origin repository mirrored from GitHub, so those runs use the ci/github form. For Entire repositories, see Authenticate to cloud providers with OIDC.
The ci/code form applies only to standalone Depot Code repositories, which have no GitHub upstream. A Depot Code repository that mirrors a GitHub repository uses the ci/github form. Depot Code accepts a push to a mirror only after GitHub accepts it, so the commit always exists on GitHub.
Runs for Origin-hosted repositories and standalone Depot Code repositories previously used ci/github in the sub claim. If a trust policy matches an Origin-hosted repository with ci/github, change it to ci/origin. If a trust policy matches a standalone Depot Code repository with ci/github, change it to ci/code.
If the repository name doesn't have the expected format or the run has no Git ref, the sub claim omits the forge, repository, and ref: spiffe://identity.depot.dev/org/<orgID>/sandbox/<sandboxID>.
Match the segments you want to restrict, and use a wildcard for the rest. Do not include the final segment in the match, because Depot generates a new sandbox ID for each job, and a policy that pins it stops matching on the next run.
| Segment | Stability | Safe to pin? |
|---|---|---|
spiffe://identity.depot.dev | Fixed. The trust domain and issuer. | Yes. |
org/<orgID>Example: org/1a2b3c4d | Stable for the life of your Depot organization. | Yes, recommended on every policy. |
ci/<forge>/<owner>/<repo>Example: ci/github/my-org/my-repo | Stable per repository. <forge> is github, entire, origin, or code. Entire adds a <namespace> segment before <owner>. | Yes. |
ref/<ref>Example: ref/refs/heads/main | The full Git ref, including the refs/heads/ prefix. Stable per branch or tag; changes when the branch does. | Yes, to lock a role to one branch. The ref contains slashes, so it spans more than one path segment. |
sandbox/<sandboxID>Example: sandbox/snd_9x8y7z | Per run. A fresh sandbox ID is minted for every job. | No. Pinning this segment breaks every subsequent run. |
Common patterns:
- Everything in your GitHub organization:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/* - Everything in your Origin namespace:
spiffe://identity.depot.dev/org/<orgID>/ci/origin/<owner>/* - A specific repository:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/* - A specific branch:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/ref/refs/heads/main/sandbox/*
Matching precisely on your cloud provider
How you pin the identity beyond the sub prefix depends on which claims your cloud provider exposes as trust-policy condition keys.
On AWS, a self-managed OIDC provider surfaces only the standard claims as IAM condition keys: aud and sub (along with amr, email, and oaud). The GitHub-compatible and Depot-specific claims (repository, repository_owner, ref, and the rest) travel inside the token but are not available as identity.depot.dev:<claim> condition keys, so a trust policy that references them never matches. On AWS, match the sub claim with StringLike as shown in Example: Configure OIDC with AWS. The sub value already encodes the org, owner, repo, and ref, so a single sub condition is enough to restrict access to a repository or branch.
On providers that map arbitrary token claims into their trust conditions, such as GCP workload identity federation, you can match the flat claims directly (repository, repository_owner, ref, and the rest of the claim reference below). These are exact-match values, so on those platforms you can pin them exactly instead of wildcarding the sub path. Most of these claims carry the same meaning as their GitHub Actions equivalents. The repository_id and repository_owner_id claims depend on the forge. See Repository and owner IDs by forge.
Configure OIDC with your cloud provider
The general steps are the same for any OIDC-compatible provider:
- Add
https://identity.depot.devas a trusted OIDC issuer. - Create a role or service account that grants access based on token claims.
- Request the token in your workflow and use it to authenticate.
Example: Configure OIDC with AWS
-
Add Depot CI as an identity provider in AWS IAM.
- Provider URL:
https://identity.depot.dev - Audience:
sts.amazonaws.com
- Provider URL:
-
Create an IAM role with a trust policy.
Scope the trust policy using the
subclaim (matching on Depot org and GitHub repository) andaud:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": {"Federated": "arn:aws:iam::ACCOUNT:oidc-provider/identity.depot.dev"}, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "identity.depot.dev:aud": "sts.amazonaws.com" }, "StringLike": { "identity.depot.dev:sub": "spiffe://identity.depot.dev/org/<orgID>/ci/github/my-org/my-repo/*" } } } ] }The
subclaim scopes trust to a specific Depot org and GitHub repository. -
Use the role in a workflow.
Set
permissions: id-token: writeat the job level. Depot CI automatically injects the token request credentials into the environment, soaws-actions/configure-aws-credentialsworks without any extra configuration.jobs: deploy: runs-on: depot-ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/my-role aws-region: us-east-1 - run: aws s3 ls
Migrate from GitHub Actions OIDC
permissions: id-token: write is required in your workflow YAML, the same as GitHub Actions.
The following needs to change on the cloud provider side when moving from GitHub Actions to Depot CI:
| GitHub Actions | Depot CI | |
|---|---|---|
Issuer (iss) | https://token.actions.githubusercontent.com | https://identity.depot.dev |
Subject (sub) | repo:owner/repo:ref:refs/heads/main | spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID> |
| Repo/branch scoping | sub (encoded in the subject) | sub (new format — see above) |
| JWKS endpoint | https://token.actions.githubusercontent.com/.well-known/jwks.json | https://identity.depot.dev/keys |
To use Depot CI with OIDC, follow these steps:
-
Add
https://identity.depot.devas a new identity provider in your cloud provider. -
Create a new trust policy for Depot CI. Creating a new policy rather than modifying your existing GitHub Actions trust policy lets both providers work in parallel during the transition.
-
If your existing trust policy conditions on
sub, update it to use the Depot CI format:spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/ref/<ref>/sandbox/<sandboxID>For more specific matches, use a wildcard:
-
Everything in your GitHub organization:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/* -
A specific repository:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/* -
A specific branch:
spiffe://identity.depot.dev/org/<orgID>/ci/github/<owner>/<repo>/ref/<ref>/sandbox/*
-
Token claim reference
Standard claims
| Claim | Description |
|---|---|
iss | Issuer: https://identity.depot.dev |
sub | Job identity. See Restrict trust policies with the subject claim. |
aud | Audience — set by the workload request (for example sts.amazonaws.com) |
exp | Expiry time (5 minutes from issuance) |
iat | Issued at time |
GitHub Actions-compatible claims
| Claim | Description |
|---|---|
repository | owner/repo |
repository_owner | Repository owner |
repository_id | Repository ID assigned by the forge |
repository_owner_id | Owner ID assigned by the forge |
repository_visibility | public, private, or internal |
ref | Git ref, for example refs/heads/main |
ref_type | branch or tag |
sha | Commit SHA |
actor | Triggering user login |
actor_id | Triggering user ID |
event_name | Trigger event, for example push, pull_request |
head_ref | PR head branch |
base_ref | PR base branch |
workflow | Workflow file path |
workflow_ref | owner/repo/path@ref |
workflow_sha | Commit SHA of the workflow file |
run_id | Workflow run ID (groups jobs in a workflow run) |
run_number | Run number for the workflow |
run_attempt | Attempt number |
Repository and owner IDs by forge
The forge assigns the repository_id and repository_owner_id values. The values depend on the forge claim:
forge | repository_id | repository_owner_id |
|---|---|---|
github | GitHub repository ID | GitHub user or organization ID |
origin | Cursor Origin repository ID | Cursor Origin owner ID |
entire | Entire repository ID, such as repo_01M2MC14M5R2TT9MEXVT0XMQ2Q | Entire project ID of the project that owns the repository |
code | Depot Code repository ID | Depot organization ID, the same value as org_id |
Two forges can use the same ID for different repositories or owners. If a trust policy matches repository_id or repository_owner_id, also match forge.
A Depot Code repository that mirrors a GitHub repository reports forge: github and the GitHub IDs.
Depot-specific claims
| Claim | Description |
|---|---|
org_id | Depot organization ID |
job_id | Depot CI job ID |
forge | Forge that hosts the repository: github, entire, origin, or code. When sub includes a forge segment, the two values match. A Depot Code mirror of a GitHub repository reports github. |