DEV Community

Cover image for Setting Up an SSH Key for GitHub: Commands, Output and Fixes
Moksh Gupta
Moksh Gupta

Posted on Originally published at devtoollab.com

Setting Up an SSH Key for GitHub: Commands, Output and Fixes

Getting Git to talk to GitHub over SSH takes four commands, and almost nobody gets through them on the first try without tripping on something: wrong file permissions, an agent that isn't running, a repo still cloned over HTTPS. I wrote the full walkthrough on DevToolLab with every output captured on OpenSSH 10.3; this is the condensed version, following one laptop and one repo (acme/billing-api) from nothing to a working push.

Pick Ed25519 and make the key

Use Ed25519. It's what GitHub's docs tell you to use, and since OpenSSH 9.5 (October 4, 2023) it's what ssh-keygen produces when you don't ask for anything else. RSA 4096 is only for old servers that can't do Ed25519, and DSA keys stopped being accepted by GitHub on March 15, 2022.

The same command works in Terminal on macOS and Linux, and in PowerShell or Git Bash on Windows 10 (1809+) and Windows 11, where the OpenSSH client ships as an optional feature:

$ ssh-keygen -t ed25519 -C "dev@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/you/.ssh/id_ed25519):
Enter passphrase for "/Users/you/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/you/.ssh/id_ed25519
Your public key has been saved in /Users/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:kifYqisf9kScRjNaxtAuIvhOta4Xa0ep4fjGK2DpyGg dev@example.com
Enter fullscreen mode Exit fullscreen mode

Don't skip the passphrase. A key without one is a file anyone with a copy of your home directory can push with. And if ssh-keygen offers to overwrite an id_ed25519 you already have, decline and give it a new name like id_ed25519_work; replacing the old key quietly locks you out of everything that trusted it.

No terminal you're allowed to use? The Ed25519 Key Generator builds the same OpenSSH-format pair in a browser tab without uploading it. It leaves the passphrase off, so run ssh-keygen -p -f ~/.ssh/id_ed25519 once the file is on your machine.

Hand the key to ssh-agent

The agent keeps the unlocked key in memory, so you type the passphrase once per session instead of on every push.

On macOS the agent is already running. Use Apple's own ssh-add (not a Homebrew copy) so the passphrase lands in Keychain, and add a ~/.ssh/config entry so it survives a reboot:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode
Host github.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode

Before Monterey (12.0) that flag was -K. On Linux, start an agent for the shell with eval "$(ssh-agent -s)" and then ssh-add ~/.ssh/id_ed25519. On Windows, enable and start the ssh-agent service from an admin PowerShell, then run ssh-add from a normal one. If Git for Windows keeps nagging for the passphrase, it's using its bundled ssh.exe; point it at C:/Windows/System32/OpenSSH/ssh.exe with git config --global core.sshCommand.

Give GitHub the public half

Only the .pub file goes to GitHub. Copy it (pbcopy < ~/.ssh/id_ed25519.pub on macOS), then go to your profile picture, Settings, SSH and GPG keys, New SSH key. Name it after the machine, keep the type as Authentication Key, paste, save.

With the GitHub CLI already signed in, it's one line:

gh ssh-key add ~/.ssh/id_ed25519.pub --title "Work MacBook 2026" --type authentication
Enter fullscreen mode Exit fullscreen mode

One gotcha: authentication and commit signing are separate on GitHub. Signing commits with the same key means uploading it again as a Signing Key.

Test it, and actually check the fingerprint

Run ssh -T git@github.com. On the first connection SSH shows GitHub's host fingerprint and asks if you trust it. Check it against GitHub's published list before saying yes. The Ed25519 one is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU, and you can confirm what the server is serving without connecting:

$ ssh-keyscan -t ed25519 github.com 2>/dev/null | ssh-keygen -lf -
256 SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU github.com (ED25519)
Enter fullscreen mode Exit fullscreen mode

GitHub Docs page listing GitHub's SSH key fingerprints for RSA, DSA, ECDSA and Ed25519, with the known_hosts entries for github.com

Success looks like Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access., with exit code 1. That non-zero exit is expected: GitHub authenticates you and then declines to give you a shell.

Move the repo off HTTPS

A clone made over HTTPS ignores your new key until you change its remote:

$ git remote set-url origin git@github.com:acme/billing-api.git
$ git remote -v
origin  git@github.com:acme/billing-api.git (fetch)
origin  git@github.com:acme/billing-api.git (push)
Enter fullscreen mode Exit fullscreen mode

Running more than one key? Put IdentitiesOnly yes in the Host github.com block, or SSH will offer every key in the agent and can hit the server's attempt limit before reaching the right one. ssh -G github.com shows the config SSH actually resolved. The SSH Config Generator will write that block for you if you'd rather not do it from memory.

The four errors you'll probably see

  • Permission denied (publickey): GitHub rejected every key offered. Check ssh-add -l, that the remote user is git, and that the matching .pub is on GitHub. Add -v to the test command and SSH prints every key it offers, one per line.
  • WARNING: UNPROTECTED PRIVATE KEY FILE! with bad permissions: the key is readable by others, usually after copying it between machines. chmod 600 the key and chmod 700 ~/.ssh.
  • incorrect passphrase supplied to decrypt private key: there's no recovery. Make a new key, upload it, delete the old one from GitHub.
  • Key already in use: that public key is attached to another account or is a deploy key somewhere. ssh -T -ai ~/.ssh/id_ed25519 git@github.com tells you who owns it.

The original article has the exact message text for each, which is what you'll want when you paste one into a search box.

Where not to use your personal key

Build machines and servers shouldn't carry your personal key. They should get credentials limited to a single repository, like a deploy key or a GitHub App token, so one compromised runner can't touch everything your account can. And keep private keys off websites and off the clipboard; generate the key on the machine that will use it.

The short version

Four commands: ssh-keygen -t ed25519, ssh-add, upload the .pub, ssh -T git@github.com. Separate keys for work and personal accounts, each with IdentitiesOnly yes. And when Permission denied (publickey) shows up, add -v before generating a new key, because the key is usually fine and just isn't the one being offered.

References

Top comments (0)