Introduction
Authenticating to a Git remote is mostly invisible until it goes wrong. The two main mechanisms are SSH keys and HTTPS credentials (passwords or, more commonly today, personal access tokens).
SSH keys
Generate a modern key:
ssh-keygen -t ed25519 -C "[email protected]"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519 # macOS
ssh-add ~/.ssh/id_ed25519 # Linux
Add the public key (~/.ssh/id_ed25519.pub) to your hosting account. Test:
ssh -T [email protected]
# Hi ada! You've successfully authenticated...
SSH config
Per-host overrides go in ~/.ssh/config:
Host github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
HTTPS credentials
Most hosts no longer accept account passwords; use a personal access token (PAT) with the right scopes. Git stores it via a credential helper:
git config --global credential.helper cache # in-memory, expires
git config --global credential.helper "cache --timeout=86400"
git config --global credential.helper osxkeychain # macOS
git config --global credential.helper manager # Windows
git config --global credential.helper store # plaintext file (only if you must)
The first time you push, Git prompts and the helper saves the token.
Inspecting and clearing
echo "url=https://github.com" | git credential fill
echo "url=https://github.com" | git credential reject
git credential is a low-level interface to the helper.
Per-host helpers
git config --global credential.https://github.com.helper manager
git config --global credential.https://gitlab.com.helper cache
Useful when different hosts require different auth methods.
Signing commits and tags
Authentication and signing are different. Signing proves authorship of a commit:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git commit -S -m "Signed commit"
git log --show-signature -1
2FA and SSO
If your host requires 2FA, HTTPS auth needs a PAT (passwords are blocked). For SSO-protected orgs, the PAT must also be SSO-authorized; otherwise pushes get a vague "permission denied" error.
Per-URL credentials
Git's credential system can store different credentials per host or path. The match key is the URL prefix, so you can have separate tokens for, say, your personal and work GitHub orgs:
git config --global credential.https://github.com/work-org.helper manager
git config --global credential.https://github.com/personal.helper "store --file ~/.git-creds-personal"
git credential fill <<<"url=https://github.com/work-org/repo"
The credential.useHttpPath setting tells Git to include the path in the lookup key, allowing per-repo credentials. Use it only when needed; it multiplies the number of stored entries.
Common mistakes
Pushing with a token that lacks the right scopes (e.g. read-only); the error message is generic. Granting overly broad scopes "to be safe"; minimize. Storing tokens in credential.helper store on shared machines; it is a plaintext file. Forgetting to upload your SSH public key to the host and being baffled by "permission denied (publickey)"; ssh -vT git@host shows what is happening. Finally, mixing protocols: ensure your remote URL matches your auth method; git remote set-url can switch.