9.3 OpenID Connect (OIDC) & Workload Identity Federation

Key Takeaways

  • OpenID Connect (OIDC) eliminates the need for long-lived, static cloud credentials (such as AWS access keys, Azure service principal client secrets, or GCP service account keys) by exchanging ephemeral GitHub-issued JSON Web Tokens (JWTs) for short-lived cloud IAM tokens.
  • To request an OIDC JWT, a workflow must explicitly declare the `id-token: write` permission in its `permissions` block; without this permission, the runner cannot communicate with GitHub's OIDC token service.
  • GitHub acts as the Identity Provider (IdP) with issuer URL `https://token.actions.githubusercontent.com`, minting digitally signed JWTs containing standard claims (`iss`, `aud`, `sub`, `repository`, `actor`, `workflow`, `environment`, etc.).
  • The subject (`sub`) claim forms the core trust condition, formatted as `repo:<org>/<repo>:ref:refs/heads/<branch>` for branch triggers or `repo:<org>/<repo>:environment:<env>` for environment deployments.
  • Cloud platforms (AWS IAM Role trust policy, Azure Federated Credentials, GCP Workload Identity Federation) evaluate GitHub JWT claims against strict IAM trust policies before issuing temporary, scoped credentials.
Last updated: August 2026

OpenID Connect (OIDC) & Workload Identity Federation

Historically, continuous deployment pipelines authenticated to cloud infrastructure (such as Amazon Web Services, Microsoft Azure, and Google Cloud Platform) using long-lived static credentials—such as AWS IAM Access Key/Secret Key pairs, Azure Service Principal client secrets, or GCP Service Account private JSON keys. These static secrets introduce major security vulnerabilities: they are susceptible to accidental exfiltration, require complex rotation schedules, and present an expansive blast radius if leaked.

GitHub Actions solves this problem through OpenID Connect (OIDC) and Workload Identity Federation. With OIDC, GitHub Actions acts as a trusted Identity Provider (IdP), minting short-lived, digitally signed JSON Web Tokens (JWTs) that cloud providers validate directly to exchange for temporary, scoped cloud credentials. Configuring OIDC authentication is one of the most prominent enterprise topics on the GH-200 examination.


1. OIDC Architecture & Token Exchange Lifecycle

The OIDC handshake between GitHub Actions and a target cloud provider eliminates static secrets entirely from repository settings.

+-----------------------------------------------------------------------------+
|                      OIDC TOKEN EXCHANGE LIFECYCLE                          |
|                                                                             |
|   [RUNNER JOB]          [GITHUB OIDC SERVICE]         [CLOUD PROVIDER (AWS)]|
|   (id-token: write)                                                         |
|          |                       |                              |           |
|   1. Request OIDC Token -------->|                              |           |
|          |   (via $ACTIONS_ID_TOKEN_REQUEST_URL)                |           |
|          |<-- 2. Return Signed JWT Token                        |           |
|          |    (RS256 signature, claims: sub, aud, iss)          |           |
|          |                       |                              |           |
|   3. Present JWT to Cloud STS --------------------------------->|           |
|      (AssumeRoleWithWebIdentity)                                |           |
|          |                       |                     4. Fetch JWKS        |
|          |                       |<------------------- Public Keys          |
|          |                       |                     5. Verify Signature  |
|          |                       |                     6. Match 'sub' Claim |
|          |<-- 7. Return Temporary Cloud Credentials (1 Hour) ---|           |
|          |    (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, TOKEN) |           |
|          |                       |                              |           |
|   8. Execute Cloud CLI / SDK Deployment                         |           |
+-----------------------------------------------------------------------------+

Step-by-Step Authentication Handshake

  1. Prerequisite Permission: The workflow job declares permissions: { id-token: write }. The runner agent exposes two internal environment variables: $ACTIONS_ID_TOKEN_REQUEST_URL and $ACTIONS_ID_TOKEN_REQUEST_TOKEN.
  2. JWT Request: An action (or script) calls the local token endpoint. GitHub's OIDC service generates a JSON Web Token signed with GitHub's private RS256 key.
  3. Cloud Exchange: The runner transmits the signed JWT to the cloud provider's Security Token Service (e.g., AWS STS AssumeRoleWithWebIdentity).
  4. Cryptographic Verification: The cloud provider fetches GitHub's public JSON Web Key Set (JWKS) from https://token.actions.githubusercontent.com/.well-known/jwks.json and verifies the token's cryptographic signature.
  5. Trust Policy Validation: The cloud provider validates standard claims: that the issuer (iss) matches GitHub, the audience (aud) matches the expected client ID, and the subject (sub) satisfies the IAM trust policy condition.
  6. Temporary Credential Issuance: Upon successful validation, the cloud provider returns short-lived session credentials (typically valid for 15 to 60 minutes) to the runner.

2. Anatomy of the GitHub Actions OIDC JWT Token

When GitHub mints an OIDC token, it populates the payload with rich metadata describing the exact workflow execution context.

{
  "iss": "https://token.actions.githubusercontent.com",
  "aud": "https://github.com/my-enterprise-org",
  "sub": "repo:my-enterprise-org/payment-service:ref:refs/heads/main",
  "repository": "my-enterprise-org/payment-service",
  "repository_owner": "my-enterprise-org",
  "repository_id": "74829104",
  "repository_owner_id": "1928374",
  "actor": "octocat",
  "actor_id": "583202",
  "workflow": "Deploy Production",
  "workflow_ref": "my-enterprise-org/payment-service/.github/workflows/deploy.yml@refs/heads/main",
  "workflow_sha": "f8d3b847a61d1983c27e98a12bc902341234abcd",
  "ref": "refs/heads/main",
  "ref_type": "branch",
  "sha": "b4ffde65f46336ab851b4c731e846067756f7004",
  "environment": "production",
  "runner_environment": "github-hosted",
  "exp": 1723748400,
  "iat": 1723747800
}

Critical Claims Reference

  • iss (Issuer): Always https://token.actions.githubusercontent.com. Used by cloud providers to locate the OIDC discovery endpoint.
  • aud (Audience): Defaults to the URL of the repository owner (or sts.amazonaws.com for AWS). Workflows can specify custom audiences via core.getIDToken(audience).
  • sub (Subject Identifier): The most crucial claim for security filtering. Formats include:
    • Branch push: repo:<org>/<repo>:ref:refs/heads/<branch-name> (e.g., repo:acme-corp/api:ref:refs/heads/main)
    • Tag push: repo:<org>/<repo>:ref:refs/tags/<tag-name> (e.g., repo:acme-corp/api:ref:refs/tags/v1.0.0)
    • Environment deployment: repo:<org>/<repo>:environment:<environment-name> (e.g., repo:acme-corp/api:environment:production)
    • Pull request: repo:<org>/<repo>:pull_request
  • environment: Present only if the workflow job explicitly targets a GitHub deployment environment (environment: production).

3. Configuring Cloud Provider Trust Policies

To establish trust, cloud IAM roles must define trust policies that evaluate GitHub's OIDC claims.

1. Amazon Web Services (AWS IAM Role Trust Policy)

AWS IAM validates GitHub OIDC using an Identity Provider configured for token.actions.githubusercontent.com.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
          "token.actions.githubusercontent.com:sub": "repo:acme-corp/payment-service:ref:refs/heads/main"
        }
      }
    }
  ]
}

AWS Workflow Implementation

name: AWS OIDC Deployment
on:
  push:
    branches: [main]

permissions:
  id-token: write # Mandatory for requesting the OIDC JWT token
  contents: read  # Required for repository checkout

jobs:
  deploy-aws:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsProductionRole
          aws-region: us-east-1
          audience: sts.amazonaws.com

      - name: Deploy to S3
        run: aws s3 sync ./dist s3://my-prod-bucket

2. Microsoft Azure (Federated Identity Credentials)

Azure uses Federated Identity Credentials attached to an Azure Active Directory (Microsoft Entra ID) Application or User-Assigned Managed Identity.

  • Issuer: https://token.actions.githubusercontent.com
  • Subject Identifier: repo:acme-corp/payment-service:environment:production
  • Audience: api://AzureADTokenExchange

Azure Workflow Implementation

name: Azure OIDC Deployment
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy-azure:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: Azure Login via OIDC
        uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

3. Google Cloud Platform (Workload Identity Federation)

GCP utilizes a Workload Identity Pool and Workload Identity Provider that maps GitHub assertion claims to Google IAM attributes:

  • Attribute Mapping: google.subject=assertion.sub, attribute.repository=assertion.repository
  • Attribute Condition: assertion.repository == 'acme-corp/payment-service'

GCP Workflow Implementation

name: GCP OIDC Deployment
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy-gcp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
          service_account: 'github-deployer@my-gcp-project.iam.gserviceaccount.com'
Loading diagram...
OpenID Connect (OIDC) Workload Identity Federation Handshake
Test Your Knowledge

A developer is configuring a workflow to authenticate with AWS using OpenID Connect via aws-actions/configure-aws-credentials@v4. When the job executes, the action fails with the error: Error: Credentials could not be retrieved: ACTIONS_ID_TOKEN_REQUEST_URL not set. What is the root cause of this failure?

A
B
C
D
Test Your Knowledge

An AWS IAM Role trust policy is configured to allow GitHub Actions deployments exclusively from pull requests targeting the release branch of the enterprise/core-api repository. Which condition block correctly enforces this least-privilege boundary in the IAM trust policy?

A
B
C
D
Test Your Knowledge

When a cloud provider (such as AWS, Azure, or GCP) receives a GitHub Actions OIDC JWT, how does the cloud provider verify that the token was legitimately issued by GitHub and has not been forged or tampered with?

A
B
C
D