Skip to content

Docker Hub Finally Does OIDC, but Only for Paying Orgs

Short-lived federated tokens replace registry PATs in GitHub Actions — unless you're on a free plan.

Emeka Okafor
Emeka Okafor
Security Editor · Aug 1, 2026 · 4 min read
Docker Hub Finally Does OIDC, but Only for Paying Orgs

There's a good chance your CI pipeline's most dangerous secret isn't a cloud key — it's the Docker Hub personal access token sitting in a GitHub repo secret. Anyone who steals it can push a poisoned image to the exact registry namespace your production clusters pull from. As of July 31, Docker has shipped the fix everyone else shipped years ago: OIDC connections that let a GitHub Actions workflow authenticate to Docker Hub with a short-lived, per-run token and no stored credential at all.

It's the right design, it works with a four-line workflow change, and it closes what was arguably the biggest remaining long-lived-credential hole in mainstream CI. It's also gated behind paid plans — and that's where my enthusiasm cools.

The last big holdout

Keyless CI authentication isn't new; Docker is late. GitHub Actions has been able to mint signed OIDC identity tokens since late 2021, and AWS, GCP, and Azure all support federating on them so workflows can touch cloud resources without stored keys. Package registries followed: PyPI launched trusted publishing in 2023, RubyGems and npm did their own versions after. By 2025 the pattern was table stakes — and the supply-chain attacks of that year, like the tj-actions/changed-files compromise that dumped CI secrets into build logs across tens of thousands of repositories, made the cost of ignoring it concrete. A leaked cloud key is bad. A leaked registry credential is arguably worse, because the blast radius is every downstream consumer of your images.

Docker Hub, the default registry for most of the container world, kept requiring a PAT or organization access token in a secret for all of that time. That's the gap this closes.

The mechanics are the standard federation dance. GitHub issues a JWT encoding the repository, branch, and environment of the run. docker/login-action presents it to Docker Hub, which verifies the signature against GitHub's public keys and matches the token's claims against rulesets you configure in Docker's Admin Console. On a match, Docker returns an access token scoped to the resources in that ruleset, which per Docker "expires in minutes and cannot be reused." Nothing to store, nothing to rotate, nothing to exfiltrate from your secrets store.

Four lines of YAML, one console setup

Adoption is genuinely light. You create an OIDC connection in Docker Home, define up to five rulesets per connection (which repos, branches, and workflows may access which Hub resources), and grab the connection ID. Then in the workflow:

permissions:
  contents: read
  id-token: write

steps:
  - name: Docker login
    uses: docker/login-action@v4
    with:
      username: my-org
    env:
      DOCKERHUB_OIDC_CONNECTIONID: ${{ vars.DOCKERHUB_OIDC_CONNECTIONID }}

No password field. The connection ID isn't a secret — it's useless without a valid GitHub-signed token matching your rulesets — so a plain repository variable is fine. You need docker/login-action v4.5.0 or later; v4.5.2 added better error surfacing, so just take the latest v4. When a login fails, the connection's Failures tab in Docker's console shows the incoming sub claim, which makes debugging ruleset mismatches a lookup rather than a guessing game.

Two things to get right. First, scope rulesets tightly: repo:my-org/my-repo:ref:refs/heads/main for the branch that actually publishes, not repo:my-org/*, which recreates the broad-PAT problem with extra steps. Second, a fresh gotcha: GitHub repositories created after July 15, 2026 embed immutable numeric identifiers in their default subject claims (repo:octocat@123456/my-repo@456789:...), so a ruleset pattern that works for your old repos may silently not match a new one. Check the Failures tab before assuming the feature is broken.

And actually finish the migration. Existing PATs keep working indefinitely — Docker deliberately didn't break anything — so the security win only lands when you delete the old token from GitHub secrets and revoke it in Docker Hub. An OIDC connection sitting next to a still-valid PAT is a nicer login flow, not a smaller attack surface.

The paywall problem

Here's the catch: OIDC connections are only available to organizations on Docker Team, Business, or Hardened Images plans, plus Docker-Sponsored Open Source projects. Personal accounts and free-tier orgs — a huge share of the images the ecosystem actually pulls — keep storing PATs in secrets.

I understand the commercial logic; the Admin Console rulesets live in Docker's paid management surface. But PyPI made trusted publishing free for every package on day one, precisely because credential theft from the long tail of small projects is how supply-chain attacks propagate. Gating the secure auth path behind a subscription protects the orgs least likely to be the weak link and leaves exposed the ones most likely to be. If Docker cares about Hub's supply-chain reputation, this needs to reach free accounts eventually.

There's also a competitive subtext. Plenty of teams solved this years ago by publishing to GHCR instead, where the ambient GITHUB_TOKEN gives you secretless, per-run, auto-scoped registry auth for free, on every plan. Docker Hub's OIDC support reads partly as a retention play against exactly that drift — and for free-tier users it doesn't change the calculus at all. If you're not paying Docker and your images only need to exist, GHCR remains the path of least resistance.

Verdict

For paying Docker orgs this is a no-brainer: it's an afternoon of work per repository, it deletes a genuinely dangerous class of stored credential, and there's no workflow downside — local dev and non-GitHub CI keep using PATs as before, and Docker says other CI providers will follow "based on demand" (translation: GitLab users, keep waiting). Do it this sprint, and actually revoke the PATs when you're done.

As an ecosystem story, it's a real improvement with an asterisk. Docker closed the gap with the rest of the packaging world — three years late and only for customers. The pattern won a long time ago; what shipped in July is Docker Hub finally, partially, catching up to it.

Sources & further reading

  1. Docker OIDC connections for GitHub Actions available for Docker Orgs — docker.com
  2. OIDC connections overview — docs.docker.com
  3. docker/login-action releases — github.com
  4. Docker Hub gets OIDC federation for GitHub Actions, retiring the PAT-in-a-secret pattern — dev.to
Emeka Okafor
Written by
Emeka Okafor · Security Editor

Emeka has spent over a decade tracking threat actors, vulnerability disclosures, and the evolving landscape of application security, bringing a sharp continent-spanning perspective to his reporting. He's known for translating dense CVE advisories into clear, actionable context that developers and security teams alike actually read.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading