Git can log in to GitHub with a key instead of a password or token. Generate a pair with ssh-keygen, paste the public file into Settings, SSH and GPG keys on your account, and pushes and pulls on private repositories stop asking who you are.
The setup is the same on macOS, Linux and Windows, apart from a few commands.
Most guides skip one thing. GitHub treats authentication and commit signing as separate key types, so a key meant for both must be uploaded twice (GitHub Docs, as of October 2026).
How to Check for an Existing SSH Key
Run ls -al ~/.ssh in a terminal. If a public key file shows up in the listing, you might already have a key you can reuse.
Look for id_ed25519.pub, id_ecdsa.pub or id_rsa.pub. Each has a private twin with the same name and no .pub extension, and only the .pub file ever goes to GitHub.
If the terminal says ~/.ssh does not exist, there is no key pair in the default location, according to GitHub Docs. Generate a new one in the next step.
The folder lives at ~/.ssh on macOS and Linux. On Windows it is C:\Users\YOURNAME\.ssh, and Git Bash maps ~ to the same place.
You can also run ssh-add -l to see what the ssh-agent holds right now. “The agent has no identities” only means nothing is loaded yet. A key can still be sitting on disk.
And a key on disk doesn’t prove GitHub knows about it. Run ssh-keygen -lf ~/.ssh/id_ed25519.pub to print its fingerprint, then compare it with the fingerprints listed under Settings, SSH and GPG keys.
Which SSH Key Type Should You Use?
For almost every new key, pick Ed25519. OpenSSH 9.5 (released 4 October 2023) made it the default for ssh-keygen, and the algorithm has been supported since OpenSSH 6.5 in January 2014 (OpenSSH release notes).
| Key type | ssh-keygen flag | GitHub status | Best fit |
|---|---|---|---|
| Ed25519 | -t ed25519 | Supported, used in GitHub Docs examples | Default for new keys |
| RSA | -t rsa -b 4096 | Supported, SHA-2 signatures required for newer keys | Clients too old for Ed25519 |
| ECDSA | -t ecdsa | Supported | Keeping an existing key |
| Ed25519-SK | -t ed25519-sk | Supported, key must be attached | Hardware security key |
RSA stuck around mostly out of habit. GitHub’s own 2021 traffic breakdown put ssh-ed25519 at 7.3% of requests, ssh-rsa at 45% and rsa-sha2 at 47% (GitHub blog, 2021).
RSA still works, with one condition
RSA keys generated after November 2, 2021 must use SHA-2 signatures (GitHub Docs). Older keys, with a valid_after date before that day, may keep using any signature algorithm. OpenSSH 7.2 and newer already sign with SHA-2, so a recent client handles this without any help from you.
The Go SSH client did not support RSA with SHA-2 when GitHub announced the change, so GitHub told Go users to switch to Ed25519.
DSA keys no longer work
GitHub dropped DSA (ssh-dss) on March 15, 2022, and new DSA keys cannot be added to a personal account. The 2021 announcement put DSA at an 80-bit security level (GitHub blog, 2021).
If an old machine only has a DSA key, generate an Ed25519 key instead of hunting for a workaround.
Hardware security keys
An ed25519-sk key ties authentication to a physical FIDO2 device. GitHub Docs notes that the hardware key must be attached to the computer every time the key pair is used.
How to Generate a New SSH Key

One command creates the key pair:
ssh-keygen -t ed25519 -C "your_email@example.com"
The -t ed25519 flag sets the algorithm. The -C flag adds a comment at the end of the public key, usually an email address or a machine name.
ssh-keygen starts by asking where to save the file. Press Enter to accept ~/.ssh/id_ed25519. If a key already sits at that path, type a new name or pass one up front with -f ~/.ssh/id_ed25519_work.
Next it wants a passphrase, typed twice. The passphrase encrypts the private key file on disk, so a copied file is useless without it.
An empty passphrase works, but anyone who gets the file can then authenticate as you. I’d set one. The ssh-agent in the next step means you type it once per session instead of on every push.
The command prints the fingerprint and a randomart image, and writes two files: id_ed25519 (private) and id_ed25519.pub (public).
Keep the file name consistent in every later command. GitHub docs issue 1086 reported a page where the generate step saved id_ed25519 but the next command pointed at id_rsa, which returned “No such file or directory”. GitHub has since fixed that page.
Generate a key for a hardware security key
Plug the device in first, then run ssh-keygen -t ed25519-sk -C "your_email@example.com". Touch the button on the device when prompted.
If the command fails with “invalid format” or “feature not supported”, the device does not support Ed25519. Run ssh-keygen -t ecdsa-sk -C "your_email@example.com" instead (GitHub Docs).
The remaining prompts match the standard flow, and the upload to GitHub works the same way.
How to Add the SSH Key to the ssh-agent
The ssh-agent keeps a decrypted copy of the private key in memory, so Git stops asking for the passphrase on every operation.
eval "$(ssh-agent -s)"starts the agent and prints its process ID.ssh-add ~/.ssh/id_ed25519loads the key.ssh-add -l -E sha256confirms it is loaded, shown as a SHA256 fingerprint.
macOS
Add the key to the Keychain so the passphrase survives a reboot: ssh-add --apple-use-keychain ~/.ssh/id_ed25519.
The --apple-use-keychain flag exists only in Apple’s own ssh-add. If you see ssh-add: illegal option -- apple-use-keychain, you are running a different ssh-add, such as one installed through Homebrew or MacPorts. Call Apple’s version by its full path, /usr/bin/ssh-add. On macOS releases before Monterey (12.0), the flag is -K (GitHub Docs).
Then create or edit ~/.ssh/config:
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519Write Host github.com, not Host *.github.com. One user in GitHub docs issue 23512 copied the wildcard version and still got a password prompt on clone, because the pattern needs a subdomain and plain github.com never matches it.
Linux
Use the same eval and ssh-add lines. An agent started this way ends with the shell session, so repeat them in a new terminal unless your desktop environment already runs an agent.
If ssh complains about an unprotected private key file, chmod 600 ~/.ssh/id_ed25519 fixes the permissions.
To limit how long the key stays loaded, add a lifetime in seconds: ssh-add -t 3600 ~/.ssh/id_ed25519.
Windows
Git Bash, the shell bundled with Git for Windows, runs the same eval and ssh-add lines shown above. That’s the easy route.
The built-in Windows OpenSSH agent in PowerShell takes a bit more work. In an elevated window, start the service with Get-Service -Name ssh-agent | Set-Service -StartupType Manual followed by Start-Service ssh-agent. Then add the key from a normal window: ssh-add $env:USERPROFILE\.ssh\id_ed25519.
GitHub Docs tells Windows users to run ssh-add from a terminal window without elevated permissions.
How to Add the Public Key to Your GitHub Account
Copy the contents of the .pub file, then paste it into Settings, SSH and GPG keys, New SSH key. The direct address is github.com/settings/keys.
Use whichever copy command matches your system:
- macOS:
pbcopy < ~/.ssh/id_ed25519.pub - Linux (with xclip installed):
xclip -selection clipboard < ~/.ssh/id_ed25519.pub - Windows (Git Bash):
clip < ~/.ssh/id_ed25519.pub - Windows (PowerShell):
cat ~/.ssh/id_ed25519.pub | clip
- Copy the public key with the command for your system.
- Click your profile photo in the upper-right corner of any GitHub page, then click Settings.
- Click SSH and GPG keys in the sidebar.
- Click New SSH key (or Add SSH key if the list is empty).
- Enter a title that names the machine, such as Work Laptop.
- Select the key type: Authentication Key or Signing Key.
- Paste the key into the Key field.
- Click Add SSH key and confirm access to your account if GitHub prompts for it.
An authentication key lets the machine push and pull. A signing key verifies commits. To use one key for both, upload it twice (GitHub Docs).
Paste only the .pub file. The private key never leaves your machine.
Upload from the command line
The GitHub CLI skips the browser entirely, once you have authenticated it with gh auth login.
gh ssh-key add ~/.ssh/id_ed25519.pub --type authentication
Use --type signing for a signing key. GitHub deletes SSH keys that go unused for a year (GitHub Docs), so a key on a laptop you rarely open may need to be added again.
How to Verify the Connection and Switch Repositories to SSH
Run ssh -T git@github.com. A working key prints your username and a note that GitHub does not provide shell access.
Test the connection
The first time you connect, ssh stops with “The authenticity of host ‘github.com’ can’t be established” and prints a fingerprint. GitHub’s testing page shows the ED25519 fingerprint as SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
Match it against GitHub’s published SSH key fingerprints before typing yes. ssh then saves the host key in known_hosts, so the prompt only returns if that entry changes.
The expected output looks like this:
Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access.Read the username in that message. A name that isn’t yours means the key sits on a different account. Exit code 1 is normal, because GitHub runs no remote command (GitHub Docs).
Always connect as git, never as your own username. And if the key isn’t loaded in the agent, ssh asks for the passphrase instead.
Switch an existing repository from HTTPS to SSH
Run git remote -v to see which address a local repository uses. Git stores the address of each remote repository under a short name, usually origin.
An HTTPS address looks like https://github.com/OWNER/REPOSITORY.git. The SSH form is git@github.com:OWNER/REPOSITORY.git.
Change it with one command, then run git remote -v again to confirm:
git remote set-url origin git@github.com:OWNER/REPOSITORY.git
For a fresh copy, cloning with the SSH address skips the switch entirely.
How to Authorize the Key for an Organization With SAML SSO
An organization that uses SAML single sign-on accepts an SSH key only after you authorize that key for the organization. Without it, the key stays blocked on the organization’s repositories even though it works on your own.
Go to Settings, SSH and GPG keys, click Configure SSO to the right of the key, then click Authorize next to the organization.
If the Configure SSO button is missing, authenticate once through your identity provider (the SAML system the organization uses for sign-in) so GitHub can link your identity. Once linked, only authorized SSH keys and personal access tokens work with that organization, even if SAML is not enforced (GitHub Docs). And if the enterprise combines SSO with an IP allow list, your IP must also be allowed at the enterprise level.
Revocation is final for that key. When an organization revokes the authorization, you cannot reauthorize the same key and have to generate and authorize a new one.
SSH certificates signed by an organization’s own certificate authority skip this step, per GitHub Docs.
Why Permission Denied (publickey) Appears and How to Fix It
Permission denied (publickey) means GitHub received no key it recognizes for your account.
| Symptom | Cause | Fix |
|---|---|---|
| Denied when connecting with your own username | Wrong user in the command | Connect as git@github.com |
| ssh-add -l lists no identities | Agent stopped or key not loaded | Start the agent, run ssh-add |
| Verbose log offers a different key file | Wrong key offered | Set IdentityFile and IdentitiesOnly yes for github.com in ~/.ssh/config |
| Key already in use | Public key attached to another account or a deploy key | Remove it from the other account or repository, or generate a fresh key if you cannot |
| Bad file number or a timeout | Firewall blocks port 22 | Use SSH over port 443 |
Read the verbose output
- Run
ssh -vT git@github.com. - Look for “Authentications that can continue: publickey”, which confirms GitHub wants a key.
- Scan the “Offering public key” lines, or filter them with
ssh -vT git@github.com 2>&1 | grep "Offering". - If your key file’s path never appears, ssh never tried it.
One variant deserves its own note. “Agent admitted failure to sign using the key” shows up in the log just before the denial, and GitHub calls it a known problem with certain Linux distributions.
Reload the key into the agent and test again.
Port 22 blocked
Some firewalls reject SSH outright. GitHub serves SSH on the HTTPS port as well, at a different hostname: ssh.github.com, not github.com.
ssh -T -p 443 git@ssh.github.com
If that prints your username, force every GitHub connection through it by adding this block to ~/.ssh/config:
Host github.com
Hostname ssh.github.com
Port 443
User gitThe first connection after the switch may warn that the host was not found in known\_hosts, or that it is known under another name. Answering yes is safe when the fingerprint matches one GitHub publishes (GitHub Docs).
GitHub Enterprise Server and GitHub Enterprise Cloud with data residency do not support SSH over the HTTPS port, so this fix won’t help there.
SSH Key or Personal Access Token: Which Fits Your Workflow?
Use an SSH key on a machine you own, and a token or deploy key everywhere else. The choice comes down to who holds the credential and how much it can reach.
| Method | Setup | Scope | Best for |
|---|---|---|---|
| SSH key | Key pair plus ssh-agent | Whole account | Your own laptop |
| HTTPS with a personal access token | Token plus credential helper | Set per token | Networks that block port 22 |
| Deploy key | One key per repository | Single repository | Servers and CI runners |
SSH key
Once the key sits in the ssh-agent, the prompts stop. There is also no token to store, rotate or paste into a config file, which is the part I like most.
The downsides are smaller. Port 22 is sometimes blocked, though the 443 fallback covers that. And the private key lives on disk, so a lost laptop means revoking it.
Personal access token
HTTPS is easier to set up than SSH and usually passes through strict firewalls and proxies, according to GitHub Docs. It works wherever HTTPS works, and each token carries its own scope.
Git does ask for credentials on every pull and push until a credential helper such as Git Credential Manager caches them. Password-based authentication for Git was also removed, so the password prompt now takes a token.
Creating a personal access token takes a few minutes in GitHub’s settings.
Deploy keys
A deploy key is an SSH key that grants access to a single repository. It can be read-only, and that is the setting to prefer. In the web interface, new deploy keys are read-only unless you tick Allow write access.
A deploy key with write access can perform the same actions as an organization member with admin access, or a collaborator on a personal repository (GitHub REST API docs). Deploy keys are also immutable, so a wrong setting means deleting the key and adding it again.
Read the Docs ran into this in 2025. Private repositories added to Read the Docs Business before April 23, 2025 could end up with a write-access deploy key, and the team migrated existing keys to read-only where possible (Read the Docs, July 2025).
The upsides are a narrow scope, a read-only option and no personal account involved. The catch is one key per repository, and GitHub allows each public key on only one account or deploy key.
Skip the shortcut of copying your personal key onto a server or CI runner. A deploy key limits the damage to one repository.
You may not need a key at all
GitHub Desktop users can clone repositories without handling SSH keys, according to GitHub’s own troubleshooting page.
If GitHub Desktop is your only Git client, the whole key setup above is optional.
SSH Key FAQ
What exactly does GitHub store when you add an SSH key?
GitHub stores only the public key. The private key stays on your machine.
The public key text alone cannot authenticate anyone, because every login needs the matching private file.
Can I use different SSH keys for multiple GitHub accounts?
Yes. Generate one key per account, since GitHub attaches each public key to a single account.
Then give each key a Host alias in ~/.ssh/config with HostName set to github.com, its own IdentityFile, and IdentitiesOnly yes. Clone through the alias, for example git@github-work:ORG/REPO.git.
How do I delete or replace an SSH key on GitHub?
Open Settings, SSH and GPG keys, then click Delete next to the key.
To rotate, add the new key first, confirm it with ssh -T git@github.com, and delete the old one last.
How do I sign commits with an SSH key?
Upload the public key as a Signing Key, then point Git at it:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Does GitHub Enterprise Server use the same steps?
Yes, with one change. Keys go to your account on the instance, and the test command uses your instance hostname: ssh -T git@HOSTNAME.
Can I generate the key with PuTTYgen on Windows?
Yes. Copy the text from the box labeled for pasting into an OpenSSH authorized\_keys file, not from the saved public key file.
RSA keys need PuTTY 0.75 or later to sign with SHA-2 (GitHub blog, 2021).
Which SSH Keys Should Stay on Your Account?
Keep one SSH key per machine you still use, and nothing else. Every extra key on the account is a credential that reaches every repository you can access.
When you review the list, start by deleting keys from retired machines. Replace legacy key types with Ed25519 next, and switch deploy keys to read-only last.
The order follows blast radius. A key from a lost laptop opens the whole account, while a legacy key type is a smaller risk on a machine you still control.
One key per machine has a cost: more entries to review. The payoff is that a lost laptop means deleting one entry instead of rotating a shared key everywhere.
This advice was checked against GitHub Docs in October 2026, and a change to the supported key types would alter the second step. Once the key is in place, pushing a first commit to GitHub is the natural next move.
- MongoDB Cheat Sheet - October 20, 2026
- Adding AI Video Generation to a Software Product: Architecture, Cost Guardrails and QA - October 20, 2026
- Show Hidden Characters, Spaces, and Line Endings in Notepad++ - October 19, 2026




