Self-hosted service
docker/docker-credential-helpers avatar
docker/docker-credential-helpers

Docker credential helpers: keeping registry logins out of config.json

Programs to keep Docker login credentials safe by storing in platform keystores

1,322 stars196 forksGoMIT

At a glance

What is it?
The docker-credential-helpers repository is a suite of small Go programs that let the Docker engine read and write registry credentials in the native secret store of the platform, macOS keychain, D-Bus secret service, Windows credential manager or a pass vault. The protocol is four verbs and a line of JSON.
Who is it for?
The Docker credential helpers fit a machine that has a real secret store, which is every developer laptop with a keychain, a desktop Linux with a D-Bus secret service, and a Windows workstation, and a team that would rather not have registry tokens sitting in a JSON file. They are the wrong tool for a CI runner with no keystore, where a helper adds a process and a protocol without adding protection, and they are the wrong tool for a secret that is not a registry credential.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The helper protocol is four verbs and one JSON document

The design of this repository is small enough to state completely, and that is its main strength.

A credential helper can be any program that can read values from the standard input. The first argument on the command line says which operation to perform, and there are four valid values.

`store` adds credentials to the store, and the payload on standard input is a JSON document with `ServerURL`, `Username` and `Secret`. `get` retrieves credentials, and its payload is the raw value for the `ServerURL`. `erase` removes credentials, and its payload is the raw value for the `ServerURL` as well. `list` lists the stored credentials, and it has no standard input payload at all.

So the entire contract between the Docker engine and a helper is: a program name, one of four verbs, and either a JSON object or a URL on standard input. Anything that implements that can be a credential store for Docker, and the engine does not care what is on the other side of it.

The repository is written in Go, and it ships the libraries to implement a new helper as well as the four shipped ones. The README describes how little work that is: implement the `credentials.Helper` interface in your own package, create a main program in your package's `cmd` directory, and add make tasks to build the program and run the tests. The `osxkeychain` directory is the worked example.

The licence is MIT, with the text in the `LICENSE` file, and the project is not archived, with the last push on 2026-10-09 and release v0.9.10 published the same day.

One line of config.json switches the engine over

Using a helper with the Docker engine is a configuration change, and it is a very small one.

The `credsStore` option goes in the `~/.docker/config.json` file, and its value is the suffix of the helper program you want to use. Setting it to `osxkeychain` means the engine will use `docker-credential-osxkeychain`.

json
{
  "credsStore": "osxkeychain"
}

That is the whole installation on the Docker side. The other half is on the host: download the binary that matches the platform from the Releases page and put it in your `$PATH`, so Docker can find it.

shell
$ cp bin/build/docker-credential-osxkeychain /usr/local/bin/

The `$PATH` requirement is the part that causes confusion. The engine does not have a configuration option for the path to the helper, it looks the program up the way it looks up any other command, so a helper that is not on `PATH` is a helper that is not installed, and the error surfaces as a failed login rather than as a missing file.

It is also worth being clear about what this changes. Without a helper, the Docker engine keeps registry credentials in the `config.json` file itself, in the `auths` section, base64 encoded. Base64 is an encoding, not encryption. With a helper, the engine sends the credential to a program that hands it to the operating system's secret store, and the file on disk no longer carries the token.

Four backends, and one of them needs GPG

The shipped programs are named after the stores they talk to, and each one is a thin adapter.

`osxkeychain` uses the OS X keychain as the credentials store. `secretservice` uses the D-Bus secret service, which is the standard desktop secret service on Linux desktops. `wincred` uses the Windows credentials manager. `pass` uses the `pass` password manager.

The `pass` one comes with a caveat that the README states plainly. `pass` has to be configured for `docker-credential-pass` to work properly, it has to be initialised with a `gpg2` key ID, and the GPG key has to exist in the `gpg2` keyring, because `pass` uses `gpg2` rather than the regular `gpg`. That is a real setup burden, and it is the kind of detail that is easy to skip and then wonder about when the helper fails to find a key.

The other three are one binary each and no configuration, which is why they are the ones most people end up using.

The `secretservice` helper is the interesting case on Linux desktops, because it means the Docker credential lives in the same protected store as everything else the desktop keeps there, and it is unlocked by the same login session. The consequence is that a headless Linux server usually has neither a keychain nor a session bus, which is the environment where a helper is least useful.

Other tools can call a helper through the client package

The helpers are not only for the Docker engine. The `client` sub-package includes functions to call external helper programs from your own command line applications, and the README lists the three things you need to know to interact with a helper.

First, the name of the program to execute, for instance `docker-credential-osxkeychain`. Second, the server address that identifies the credentials, for instance `https://example.com`. Third, the username and secret to store, when you want to store credentials.

That is the whole interface, and it is the same interface the engine uses, which is the useful part: a deployment tool, a CI helper or a secret rotation script can read and write the same store that Docker uses, without a second copy of the credential and without inventing a new secret format.

The `client` package documentation has examples of each function, and the repository keeps the shared logic in the `credentials/` package, the caller side in `client/`, and a `registryurl/` package for working with registry URLs, which is the piece that has to agree with the engine on what counts as the same server.

For a team that already has a secret store and a lot of tools that need the same registry credential, this is the part that makes the suite more than a Docker plugin.

Cross-compiled binaries, and the Mac deployment target

Building the helpers is where the repository gets serious, because each one links against a platform library and the platforms are not equivalent.

The documented path builds with Docker and buildx, which lets you produce a binary for a platform you are not on:

shell
# install emulators
$ docker run --privileged --rm tonistiigi/binfmt --install all

# create builder
$ docker buildx create --use

# build credential helpers from remote repository and output to ./bin/build
$ docker buildx bake "https://github.com/docker/docker-credential-helpers.git"

The same bake works against a local checkout, and the Dockerfile carries the versions as build arguments, including the Go version, the Debian variant, the `xx` cross-compilation helper, the osxcross toolchain for macOS and the golangci-lint image:

dockerfile
ARG GO_VERSION=1.26.9
ARG BASE_DEBIAN_DISTRO=trixie
ARG XX_VERSION=1.9.0
ARG OSXCROSS_VERSION=11.3-r8-debian

With a local toolchain the route is a make target per helper, and the executable lands in the `bin` directory of the repository:

shell
$ make osxkeychain

The Makefile holds two details that explain the shape of the build. The macOS deployment target is exported as 10.11, with a comment that 10.11 is the minimum supported version for osxkeychain, and the CGO flags differ between macOS and everything else, where a flag suppresses an atomic alignment warning that is turned into an error by the newer toolchains. There is also a special case for `linux/arm/6`, where the CGo compiler and the C toolchain do not link `libatomic` automatically because the architecture does not support atomic intrinsics, so the build adds `-latomic` by hand.

That last case is a good summary of the project: a small program that has to link against four different platform secret stores, and therefore has to care about which architecture and which toolchain produced it.

Two retracted releases and a reason to pin

The `go.mod` file contains something that is worth reading before you pin a version.

go
retract (
	v0.9.1 // osxkeychain: a regression caused backward-incompatibility with earlier versions
	v0.9.0 // osxkeychain: a regression caused backward-incompatibility with earlier versions
)

Two versions are retracted, and the reason in both cases is the same: the osxkeychain helper regressed in a way that broke backward compatibility with earlier versions. The Go module mechanism uses a retraction to tell tooling that a version should not be selected, so this is the project telling every module resolver to skip v0.9.0 and v0.9.1.

The releases around them are v0.9.8 from 2026-06-08, v0.9.9 from 2026-08-26 and v0.9.10 from 2026-10-09. A user who pins a helper binary to a specific tag to keep a fleet consistent is well advised to pick one of the three that is not retracted.

The module is `github.com/docker/docker-credential-helpers`, it declares Go 1.21, and it has two direct dependencies, `github.com/danieljoos/wincred` for the Windows credential manager and `github.com/keybase/go-keychain` for the OS X keychain, with `golang.org/x/sys` as an indirect dependency. The `vendor/` directory is committed, and the Dockerfile sets `GOFLAGS` to `-mod=vendor` with `CGO_ENABLED=1`, so a build does not reach out to the module proxy.

Where a credential helper is the wrong tool

The limits follow from what the protocol is.

A helper stores registry credentials, and nothing else. It is a program that answers `get` for a `ServerURL`, and it is not a general purpose secret store for an application to keep API keys in. A team looking for one mechanism to hold every secret in the product will not find that here.

On a machine with no keystore, a helper is overhead. A CI runner with no session bus, no keychain and no credential manager gains nothing from a helper binary, and gains a process and a protocol on every login. The base64 `auths` entry in `config.json` is not encryption, but on a runner where the config file is already protected by the runner's own isolation, the difference is theoretical.

The `pass` helper is a special case of that: it turns a keystore into a requirement, because it needs a GPG2 key ID, a GPG2 keyring and an initialised password store before a single login can work.

There is also a portability cost that comes with the design. The helper is a separate executable that has to exist at the same path on every machine, with the right name, built for the right architecture, and the engine will not tell you clearly when it is missing. A team that supports several operating systems ends up distributing helper binaries along with Docker itself.

The alternative approach is to keep the credential in the Docker configuration file, which is what the engine does by default, and to protect that file with the permissions and the secret handling of the machine instead. The difference in approach is that the helper delegates the problem to the operating system's secret infrastructure, so the protection is as good as the keychain and the protection is also as available as the keychain, and the file-based route keeps everything in one place and depends on nothing but file permissions.

Editorial conclusion

The Docker credential helpers fit a machine that has a real secret store, which is every developer laptop with a keychain, a desktop Linux with a D-Bus secret service, and a Windows workstation, and a team that would rather not have registry tokens sitting in a JSON file. They are the wrong tool for a CI runner with no keystore, where a helper adds a process and a protocol without adding protection, and they are the wrong tool for a secret that is not a registry credential. Before adopting them, check that a helper binary is actually on `PATH` on every machine that runs the engine, since a missing binary is what produces the confusing failures, and note that the `pass` helper needs a GPG2 key ID configured, and that versions v0.9.0 and v0.9.1 were retracted for an osxkeychain regression that broke compatibility with earlier releases.

Frequently asked questions

How do I make Docker use a credential helper?

Set the `credsStore` option in your `~/.docker/config.json` file to the suffix of the helper you want, for example `osxkeychain` for `docker-credential-osxkeychain`, and make sure the binary is in your `$PATH` so Docker can find it.

Which credential helper stores are available?

Four are shipped: osxkeychain for the OS X keychain, secretservice for the D-Bus secret service, wincred for the Windows credentials manager, and pass for the pass password manager. The pass helper has to be configured with a gpg2 key ID, because pass uses gpg2 rather than the regular gpg.

What do the store, get, erase and list commands do in a Docker credential helper?

The first argument selects the operation. store reads a JSON document with ServerURL, Username and Secret from standard input, get and erase read the raw ServerURL value, and list takes no standard input payload.

How do I build the Docker credential helpers from source?

With Docker and buildx: install the emulators with `docker run --privileged --rm tonistiigi/binfmt --install all`, create a builder with `docker buildx create --use`, then run `docker buildx bake`. With a local toolchain, `make osxkeychain` builds one helper and leaves the executable in the bin directory of the repository.

Official sources

  1. docker/docker-credential-helpers on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/docker-docker-credential-helpers.svg)](https://hysenlabs.com/projects/docker-docker-credential-helpers)

Was this useful?