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
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
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
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
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)
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)
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. Checkssh-add -l, that the remote user isgit, and that the matching.pubis on GitHub. Add-vto the test command and SSH prints every key it offers, one per line. -
WARNING: UNPROTECTED PRIVATE KEY FILE!withbad permissions: the key is readable by others, usually after copying it between machines.chmod 600the key andchmod 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.comtells 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
- Original article on DevToolLab: How to Generate an SSH Key for GitHub
- GitHub's SSH key fingerprints
- GitHub CLI
-
Ed25519 Key Generator - an OpenSSH-format Ed25519 pair in the browser when you can't run
ssh-keygen -
SSH Config Generator - the
Host github.comblock, written for you

Top comments (0)