Docker Adds GitHub Actions OIDC, Saying Goodbye to Long-Lived CI Secrets

On July 31, 2026, Docker's official blog announced OIDC (OpenID Connect) connections for GitHub Actions. This lets CI/CD pipelines authenticate to Docker Hub with short-lived, per-run tokens instead of the long-lived personal access tokens (PATs) or organization access tokens (OATs) stored in repositories.

For teams that build images automatically with GitHub Actions, this is almost a free security upgrade: no changes to build logic, no new infrastructure — just a different way to authenticate, and the "one leaked key equals a fully exposed account" risk drops dramatically.

The pain of long-lived credentials

Every GitHub Actions workflow that pushes or pulls images from Docker Hub used to authenticate with a PAT or OAT stored as a GitHub secret. These credentials are long-lived: once leaked, an attacker can pull private images or even push malicious ones, and that access persists until someone discovers and revokes it. Rotation is manual and doesn't scale. As pipelines multiply, so do the credentials to track, and stale tokens are a common audit finding.

The OIDC approach follows the same philosophy as AWS OIDC for GitHub Actions and GCP Workload Identity Federation: trust not what you stored, but where you came from.

Dimension Traditional PAT/OAT Docker OIDC connection
Token lifetime Months to years Per-run, expires in minutes
Storage Repository secret Not stored; issued at runtime
Impact of a leak Reusable for a long time Invalid after one run
Scope Org/account level Ruleset-scoped resources
Rotation cost Manual, easy to miss No rotation needed

How it works

  1. GitHub issues a signed identity token (JWT) encoding the repository, branch, environment, and other metadata about this run;
  2. The workflow presents this token to Docker via docker/login-action;
  3. Docker verifies the signature against GitHub's public keys and checks it against the rulesets configured in the admin console;
  4. If the token matches a ruleset, Docker returns a short-lived access token scoped to that ruleset's resources;
  5. docker pull, docker push, and docker build then work as usual.

No stored secrets, API keys, or access tokens are involved, and the short-lived token expires in minutes and cannot be reused.

Migration steps

  • Create a connection: sign in to Docker Home, open your organization's OIDC connections, create a connection, and configure rulesets (up to five per connection), pinning repositories and branches with subject claims like repo:org/repo:ref:refs/heads/main.
  • Update your workflow: add permissions: id-token: write and set DOCKERHUB_OIDC_CONNECTIONID in docker/login-action.
  • Verify and clean up: run a pipeline to confirm success, then remove the old PAT or OAT from repository secrets.

The migrated workflow looks roughly like this:

name: build-and-push

on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write   # lets the job obtain this run's OIDC token

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
          oidc-connection-id: ${{ secrets.DOCKERHUB_OIDC_CONNECTIONID }}
      - run: |
          docker build -t myorg/app:latest .
          docker push myorg/app:latest

oidc-connection-id points at the connection your admin created in the console, so GitHub no longer needs any long-lived Docker credential — you can delete that DOCKERHUB_TOKEN secret once everything is verified. For teams with many repositories and branches, create separate connections for production and staging, and tighten each ruleset's subject claim so no single connection covers more resources than it should.

Things to watch during migration

  • Leave room in your rules: rulesets match repositories and branches via subject claims. Too broad and you lose the point of scoping; too strict (say, pinning the ref to refs/heads/main) and PR previews or feature-branch builds fail. A common pattern is one strict ruleset for release branches plus a looser fallback for everything else.
  • Failures are traceable: if the login step throws an OIDC-related error, check the recent attempts on the OIDC connections page in the Docker console and compare the subject claim GitHub sent against your ruleset — it's usually "branch didn't match" or "wrong connection ID".
  • Least privilege still applies: OIDC only solves authentication, not authorization. Keep the org account or namespace bound to the connection at the minimum usable permission level — don't casually grant org-wide write access.
  • Start small: migrate one low-risk repository first and confirm logs and image tags look right, then roll out to core pipelines. Rollback is quick anyway, because the old PAT stays valid until you clean it up.

Note that existing PATs and OATs keep working, so migration happens at your own pace; local development and other CI providers still use PATs/OATs, with Docker planning to expand OIDC to more platforms based on demand.

16IDC Take

"Moving secrets to the cloud and identity down to the run" is becoming the default posture for deployment automation. For site and SaaS teams, switching CI credentials from long-lived static to short-lived dynamic is a high-value, low-cost security improvement — it doesn't change how you build, yet it dramatically shrinks the blast radius of a leaked key. To build a full pipeline, start with the GitHub Actions CI/CD guide; for container and orchestration fundamentals, see the Docker deployment guide and the Kubernetes beginner's guide. For more environment and deployment content, see the Environment Deployment category.

Source: https://www.docker.com/blog/docker-oidc-connections-for-github-actions-available-for-docker-orgs/
Reference: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect (GitHub security hardening with OIDC)