Skip to content

OpenSSH Client Keys

First PublishedByAtif Alam

This page covers client-side SSH keys on a macOS workstation (Apple Silicon or Intel) for Git over SSH with GitHub and GitLab. OpenSSH is preinstalled. Optional CLIs: gh (GitHub) and glab (GitLab) for uploading keys. The same commands largely apply on Linux and WSL — see Platform Notes (Linux and WSL).

For everyday Git workflows, see Git Essentials. For commit signing with SSH keys (different from login keys), see Compliance → SSH signing.

Read Private Keys and Key Types first.

GoalSections to follow
Create and register a new keyCreateAdd to GitHub/GitLabssh-agentMulti-host configHTTPS → SSHTest
Compare or identify existing keysWhat you are comparingListFingerprintCompareWorked exampleMatch to providerAgent / verbose
Multiple accounts (GitHub + GitLab)Complete Multi-host config before Test Git Over SSH

Never commit, paste, or share private keys — files in ~/.ssh/ without a .pub suffix. Treat them like passwords.

Key typeScopeThis page
Account SSH keyYour user on GitHub or GitLab; clone and push to repos you can accessCovered below
Deploy keySingle repository (read-only or read-write)Out of scope — configure per repo in provider settings

Prefer ED25519 (small, modern):

Terminal window
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_git

Use a passphrase on laptops. You will enter it once per session (or store in Keychain via ssh-add below).

Resulting files:

FileRole
~/.ssh/id_ed25519_gitPrivate key — never share
~/.ssh/id_ed25519_git.pubPublic key — upload to GitHub/GitLab

Permissions (if ssh-keygen did not set them):

Terminal window
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519_git
chmod 644 ~/.ssh/id_ed25519_git.pub

File already exists: ssh-keygen prompts to overwrite. Prefer a new -f name (for example id_ed25519_gitlab_work) instead of clobbering a key still in use.

RSA (legacy hosts only): if a system requires RSA, ssh-keygen -t rsa -b 4096 -C "[email protected]" -f ~/.ssh/id_rsa_git. Default to ED25519 for GitHub and GitLab.

Copy the public key on macOS:

Terminal window
pbcopy < ~/.ssh/id_ed25519_git.pub

Add the key to each provider you use. The same .pub file may be registered on both GitHub and GitLab.

After upload, confirm the provider UI fingerprint matches your local key.

ProviderWeb UICLI (optional)
GitHubSettings → SSH and GPG keys → New SSH keygh ssh-key add ~/.ssh/id_ed25519_git.pub --title "MacBook"
GitLab (GitLab.com)Avatar → Edit profileAccessSSH keysAdd new keyglab ssh-key add ~/.ssh/id_ed25519_git.pub -t "MacBook"

Self-managed GitLab: use your instance hostname in HostName (see Multiple Git Hosts) and test with ssh -T [email protected].

Verify locally:

Terminal window
ssh-keygen -l -f ~/.ssh/id_ed25519_git.pub

Compare the SHA256 fingerprint to the value shown in the provider UI.

Terminal window
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_git

On older macOS releases, ssh-add -K was the equivalent flag for Keychain.

Optional ~/.ssh/config stanza so keys load into the agent and Keychain on use — without pinning one global key:

Host *
AddKeysToAgent yes
UseKeychain yes

Do not set a global IdentityFile under Host * when you use separate keys for GitHub, GitLab, personal, or work accounts.

Confirm the key is loaded:

Terminal window
ssh-add -l

Configure before ssh -T when you use host aliases. Map each alias to one private key with IdentitiesOnly yes so SSH does not offer every loaded key (avoids Too many authentication failures).

Example for GitHub and GitLab.com:

Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github_personal
IdentitiesOnly yes
Host gitlab-work
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab_work
IdentitiesOnly yes

Clone and push URLs:

Terminal window
git clone git@github-personal:org/repo.git
git clone git@gitlab-work:group/repo.git

The Host name is arbitrary; it must match the host segment in the Git URL.

Terminal window
git remote -v

GitHub (default host or alias):

Terminal window
git remote set-url origin [email protected]:org/repo.git
# or
git remote set-url origin git@github-personal:org/repo.git

GitLab (default host or alias):

Terminal window
git remote set-url origin [email protected]:group/repo.git
# or
git remote set-url origin git@gitlab-work:group/repo.git

See Git Essentials for clone and branch workflows.

Default hostnames:

Terminal window

With ~/.ssh/config aliases:

Terminal window
ssh -T git@github-personal
ssh -T git@gitlab-work

Success messages differ by provider (for example GitHub’s “Hi username!” or GitLab’s welcome text). A first connect may prompt to trust the host key — expected.

If you see Permission denied (publickey), see Troubleshooting.

You are matching:

  • Local: ~/.ssh/*.pub files on disk
  • Remote: keys registered on your GitHub or GitLab account

Fingerprints must match; the comment at the end of a .pub line is only a label.

Terminal window
ls -la ~/.ssh
SuffixMeaning
.pubPublic key — safe to upload
(none)Private key — never share
.pub absent on paired filePrivate half of a key pair
Terminal window
ssh-keygen -l -f ~/.ssh/id_ed25519_git.pub

Legacy UIs may show MD5 fingerprints:

Terminal window
ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519_git.pub
FieldExample meaning
AlgorithmED25519, RSA, ECDSA
Bit length256, 3072, …
FingerprintSHA256:… — use to match provider UI
CommentEmail or machine name — not cryptographically binding
Terminal window
ssh-keygen -l -f ~/.ssh/id_ed25519_github_personal.pub
ssh-keygen -l -f ~/.ssh/id_ed25519_gitlab_work.pub

Or diff fingerprint lines:

Terminal window
diff <(ssh-keygen -l -f ~/.ssh/key_a.pub) <(ssh-keygen -l -f ~/.ssh/key_b.pub)

Different SHA256 fingerprints mean different key pairs — not duplicates, even if comments look similar.

Scenario: You have id_ed25519_old.pub and id_ed25519_new.pub on disk. GitHub lists two SSH keys titled “MacBook” and “MacBook 2026”.

  1. Fingerprint each local file:
Terminal window
ssh-keygen -l -f ~/.ssh/id_ed25519_old.pub
ssh-keygen -l -f ~/.ssh/id_ed25519_new.pub
  1. Open GitHub → Settings → SSH and GPG keys (or GitLab → Edit profile → Access → SSH keys).
  2. Match each UI entry’s fingerprint to one local output.
  3. Note algorithm and created date in the UI (or stat on macOS):
Terminal window
stat -f "%Sm %N" -t "%Y-%m-%d" ~/.ssh/id_ed25519_old.pub ~/.ssh/id_ed25519_new.pub

You now know which file corresponds to which registered key — without re-uploading.

Use this when keys already exist on the provider and you need to identify one file on disk. Distinct from adding a new key.

Provider UI:

ProviderWhere to read fingerprints
GitHubSettings → SSH and GPG keys
GitLabEdit profile → Access → SSH keys

From the terminal:

Terminal window
ssh-keygen -lf ~/.ssh/example.pub

Optional listing (authenticated CLI):

Terminal window
gh api user/keys --jq '.[] | "\(.title) \(.key)"'
glab ssh-key list

Inspect Keys in ssh-agent and Verbose Offers

Section titled “Inspect Keys in ssh-agent and Verbose Offers”

Loaded keys:

Terminal window
ssh-add -l
ssh-add -L

Which key SSH offers (GitHub):

Terminal window
ssh -vT [email protected] 2>&1 | grep -E 'Offering|Authenticating|identity'

GitLab:

Terminal window
ssh -vT [email protected] 2>&1 | grep -E 'Offering|Authenticating|identity'

Use the same grep with your Host alias when using ~/.ssh/config.

  1. Confirm nothing still uses the old key (remotes, CI, other machines).
  2. Delete the key in the provider UI (GitHub or GitLab SSH keys page).
  3. Optionally remove the local pair: rm ~/.ssh/id_ed25519_old ~/.ssh/id_ed25519_old.pub

This is not a full key-rotation runbook — only cleanup when you know the key is retired.

SymptomThings to check
Permission denied (publickey)Public key on the account? Correct IdentityFile in ~/.ssh/config? ssh-add -l shows the key?
Wrong key offeredIdentitiesOnly yes; correct Host alias; verbose test
Too many authentication failuresToo many keys in agent; use per-host IdentityFile + IdentitiesOnly yes
Fingerprint mismatchRe-copy .pub; wrong file pasted in UI
HTTPS remote still usedSwitch remote to SSHgit remote -v should show git@
PurposeConfigDocs
AuthenticationPush and clone over SSH ([email protected], [email protected])This page
Commit signinggit config --global gpg.format ssh and user.signingkey pointing at a .pubCompliance

The same key file can sometimes be used for both on GitLab (glab ssh-key add --usage-type auth); signing policy is separate from “can I push?”

TaskmacOSLinux / WSL
Copy public keypbcopy < file.pubxclip -selection clipboard < file.pub or wl-copy < file.pub
File datesstat -f "%Sm" -t "%Y-%m-%d" filestat -c "%y" file
ssh-agentKeychain via ssh-add --apple-use-keychaineval "$(ssh-agent -s)" or user systemd unit
Config path~/.ssh/configSame under Linux home in WSL

WSL stores keys on the Linux side (~/.ssh inside the distro), not the Windows profile, unless you deliberately share them.

Path A — new key: ssh-keygen → add public key to GitHub and/or GitLab → ssh-add --apple-use-keychain → per-host ~/.ssh/configssh -T → optionally switch remote to SSH.

Path B — existing keys: fingerprint local .pub files → match provider UI → set Host alias and IdentityFile → verbose ssh -vT if the wrong key is offered.

For server-side SSH (authorized_keys, sshd), see Linux and security material elsewhere in the library — not covered here.