Skip to content
shellhacks.dev
Git

How to Use Git Credential Helpers Without Typing Passwords

Configure a Git credential helper to keep HTTPS tokens in the OS keychain or a memory cache, avoid plain text storage, and prefer SSH keys or tokens.

6 min read
Summarize in AI
Illustration for "How to Use Git Credential Helpers Without Typing Passwords": a shell script in an editor, a git branch graph, environment variables.

Every HTTPS push to a Git host asks for a username and a token unless something remembers them. That something is a credential helper, an external program that Git calls to get, store and erase credentials. The right helper depends on your system, and the wrong one stores a token in plain text. The examples use Git 2.45; the alternative with no tokens is in SSH keys for GitHub and GitLab.

Pick the helper

Shell
git config --global credential.helper osxkeychain          # macOS
git config --global credential.helper libsecret            # Linux desktop (build or package)
git config --global credential.helper manager              # Git Credential Manager (all platforms)
git config --global credential.helper 'cache --timeout=3600'
git config --global --get-all credential.helper

osxkeychain and libsecret use the operating system's secret store, so the token is encrypted at rest and tied to your login. Git Credential Manager, from Microsoft and shipped with Git for Windows, supports OAuth sign-in flows and many hosts. cache holds the credential in memory for the timeout, through a small daemon, and never writes it to disk. On Debian, libsecret comes from /usr/share/doc/git/contrib/credential/libsecret and needs building, or the package git-credential-libsecret on newer releases.

Avoid plain text storage

Shell
git config --global credential.helper store
cat ~/.git-credentials
Text
https://alice:[email protected]

store writes the token in plain text to ~/.git-credentials, readable by anything running as your user and by any backup of the home directory. Use it only on a throwaway machine, and prefer cache for servers. A token typed on the command line or in a URL also ends up in history and the process list, as in shell script secrets.

Use tokens, not passwords

GitHub and GitLab no longer accept account passwords for Git over HTTPS. Create a personal access token, or a fine-grained token limited to the repositories and permissions needed, and give it an expiry. Use it as the password when Git prompts. In automation, prefer a deploy key with SSH or a short-lived token from the CI system. Rotate a token the moment it appears in a log, a chat or a commit, as covered in removing a secret from Git history.

Fix a wrong stored credential

Shell
printf 'protocol=https\nhost=github.com\n\n' | git credential reject
git credential fill <<<$'protocol=https\nhost=github.com\n'

After a token is revoked or changed, Git keeps offering the old one and every push fails with "Authentication failed". git credential reject asks the helper to erase it, and the next push prompts again. git credential fill shows what the helper would supply, which helps when it seems to use the wrong account. Different accounts per host or path use credential.useHttpPath and per-URL configuration.

How the protocol talks to a helper

When Git needs a credential for an HTTPS remote, it runs the configured helper with a verb and sends a few lines on standard input describing the request: the protocol, host and, if known, the path and user name. The verbs are get, to retrieve a stored credential, store, to save one that worked, and erase, to delete one that was rejected. The helper answers on standard output with the same key and value lines. This simple protocol is why any program can serve as a helper, and why many exist: for the system keychain, for password managers, for cloud providers' short-lived tokens. You can test one by hand with printf 'protocol=https\nhost=github.com\n\n' | git credential fill, which prints what Git would use, and be careful, since the output contains the secret.

Several helpers can be configured and are tried in order, which makes chains possible: a cache in front of a persistent store, for example. An empty value for the option resets the list, which is how a repository-level setting can override a global one rather than add to it.

Scoping credentials to hosts and paths

The configuration can be specific to a URL: git config --global credential.https://github.com.helper manager uses one helper for one host. Setting credential.useHttpPath true makes Git include the repository path in the request, so different repositories on the same host can have different credentials. That is helpful for deploy tokens, where each repository has its own, and unnecessary for a personal token that works across them. Set credential.username per host to avoid the prompt for a name when the token is the only secret.

Tokens, expiry and rotation

Hosting services have replaced passwords with personal access tokens or OAuth flows. A token has a scope and an expiry, and the credential helper stores it until it stops working, at which point Git tries the helper again, gets the stale token, fails, calls erase and prompts for a new one. If the prompt never appears and authentication keeps failing, the helper may be returning the old token without erasing it, and clearing the entry by hand in the keychain or with git credential reject fixes it. Give each machine its own token so a lost laptop means revoking one, set an expiry that matches your rotation practice, and prefer fine-grained tokens limited to the repositories you use.

CI and automation

A build server should not use a personal credential. Use a deploy key over SSH, a machine account with the narrowest scope, or the CI platform's built-in token, and supply it through an environment variable or a secret store. A throwaway helper defined inline, git -c credential.helper='!f() { echo username=ci; echo "password=$TOKEN"; }; f' clone ..., passes the token without writing it to disk or putting it in the remote URL, where it would be visible in the process list, the shell history and the repository's configuration. Never embed a token in a URL stored in a remote, since Git prints it in error messages.

Moving to SSH or short-lived credentials

For heavy daily use, SSH keys with an agent avoid the helper entirely, and hardware-backed keys add protection against theft. Where an organisation uses single sign-on, the Git Credential Manager performs the browser-based login and refreshes tokens automatically, so no long-lived secret sits on the machine. Cloud-hosted repositories offer helpers that mint tokens from the cloud identity on demand. Whichever you pick, the goal is the same: a credential that is stored encrypted, limited in scope and time, and easy to revoke.

Where this does not apply

On developer machines with a working SSH key, skip HTTPS tokens entirely and use the SSH URL, shown in changing a remote URL to SSH. In CI, do not install a helper; use the system's own token mechanism. Shared servers where several people use one account should not store credentials at all. The protocol between Git and a helper is documented in gitcredentials and git credential, and the Windows and cross-platform tool at Git Credential Manager.

Also inSecurity
Taggedgit
Share

Keep reading

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.