SSH Keys for GitHub
SSH keys let you authenticate with GitHub over the network without typing your username and a token every time you push or pull. Instead of a password, you prove your identity with a cryptographic key pair: a private key that never leaves your computer, and a public key you upload to your GitHub account. Once set up, git push, git pull, and git clone over SSH just work, with no prompts and no long-lived token sitting in your shell history or credential store.
Overview: How SSH Authentication Works
SSH (Secure Shell) is a network protocol built on public-key cryptography. When you generate an SSH key pair, you get two files: a private key (for example id_ed25519) that must stay secret and never be shared, and a public key (id_ed25519.pub) that is safe to hand out. The two are mathematically linked: anything signed with the private key can only be verified with its matching public key, and it is computationally infeasible to derive the private key from the public one.
You upload the public key to your GitHub account settings. From then on, whenever your local git client connects to github.com over SSH, GitHub’s server issues a cryptographic challenge, and your local SSH client signs it using your private key. GitHub checks that signature against every public key registered on your account, and if one matches, you’re authenticated as that user, with no username or password ever transmitted. This differs from HTTPS authentication, where you type a Personal Access Token (PAT) or rely on a credential helper to cache one.
Compare this to Git’s own object model: a commit is identified by a SHA-1 hash of its content (a tree snapshot, its parent commits, and metadata), and trust in a commit’s integrity comes from that hash chain. SSH authentication is a completely separate layer, with nothing to do with how commits, trees, and blobs are stored. SSH only controls who is allowed to read or write to a repository over the network; it says nothing about the repository’s history, and switching a remote between SSH and HTTPS never changes a single byte of your commits.
Key types
Modern Git and GitHub recommend the ed25519 key algorithm, based on elliptic-curve cryptography: it produces short, fast keys with strong security guarantees. The older rsa algorithm (typically at 4096 bits) is still fully supported and appears in older tutorials, but there is no reason to choose it for a brand-new key today.
The SSH agent
If you protect your private key with a passphrase, which is strongly recommended since anyone who steals an unencrypted private key file can impersonate you, you’d normally be asked to re-enter that passphrase on every single SSH connection. The ssh-agent is a background program that holds your decrypted private key in memory for the length of your session, so you unlock it once and Git operations proceed silently afterward.
known_hosts and host verification
The first time you connect to github.com over SSH, your client doesn’t yet know GitHub’s server identity, so it shows you GitHub’s host key fingerprint and asks you to confirm it. Once accepted, that fingerprint is stored in ~/.ssh/known_hosts, and future connections are checked silently against it, protecting you against a man-in-the-middle silently swapping the server you think you’re talking to.
Syntax
The core command used to create a key pair:
ssh-keygen -t "<key-type>" -C "<comment>"
-t ed25519— the key algorithm to generate (ed25519recommended;rsaalso supported).-C "<comment>"— a label embedded in the public key, conventionally your email address, to help you tell keys apart later.-f <path>— optional custom output file path/name, useful when generating more than one key.
Other commands you’ll use alongside it:
| Command | Purpose |
|---|---|
ssh-agent |
Runs a background process that caches your unlocked private key for the session. |
ssh-add <path> |
Loads a private key into the running ssh-agent. |
ssh -T git@github.com |
Tests that GitHub recognizes your key, without running a real Git operation. |
gh ssh-key add <path> |
Uploads a public key to your GitHub account from the terminal using the GitHub CLI. |
git remote set-url |
Switches an existing repository’s remote URL between HTTPS and SSH. |
Examples
Example 1: Generate a new SSH key and load it into the agent
ssh-keygen -t ed25519 -C "your_email@example.com"
Output:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abcxyz1234567890examplefingerprint your_email@example.com
Pressing Enter at the file prompt accepts the default location. Choosing a passphrase encrypts the private key file at rest; leaving it empty is faster but means anyone who copies the raw file can use it immediately. Next, start the agent and register the new key with it:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Output:
Agent pid 4021
Identity added: /home/you/.ssh/id_ed25519 (your_email@example.com)
eval "$(ssh-agent -s)" starts the agent and exports the environment variables your shell needs to talk to it; ssh-add then decrypts the private key, prompting for the passphrase once, and hands it to the running agent for the rest of the session.
Example 2: Add the public key to GitHub and verify the connection
cat ~/.ssh/id_ed25519.pub
Output:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyDataOnly your_email@example.com
Copy that entire line and paste it into GitHub under Settings → SSH and GPG keys → New SSH key, giving it a descriptive title like “Work laptop”. If you have the GitHub CLI installed and authenticated, you can add it from the terminal instead:
gh ssh-key add ~/.ssh/id_ed25519.pub --title "Work laptop"
Output:
✓ Public key added to your account
Then confirm GitHub accepts the key:
ssh -T git@github.com
Output:
The authenticity of host 'github.com (140.82.121.3)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.
That “successfully authenticated” line is expected and correct; GitHub deliberately refuses an interactive shell over this connection and only uses SSH to serve Git operations. The first-run host-key prompt is normal too, and gets written to ~/.ssh/known_hosts so you won’t see it again for this host.
Example 3: Switch an existing repository from HTTPS to SSH
git remote -v
Output:
origin https://github.com/yourname/portfolio-site.git (fetch)
origin https://github.com/yourname/portfolio-site.git (push)
git remote set-url origin git@github.com:yourname/portfolio-site.git
git remote -v
Output:
origin git@github.com:yourname/portfolio-site.git (fetch)
origin git@github.com:yourname/portfolio-site.git (push)
Existing clones don’t need to be re-cloned; git remote set-url just rewrites the URL Git uses to reach the same repository. From this point on, git push and git pull on this repo authenticate via your SSH key instead of a token or password prompt. For a brand-new repository you can skip this step entirely by cloning with the SSH URL from the start:
git clone git@github.com:yourname/portfolio-site.git
How It Works, Step by Step
When you run a Git command against an SSH remote (git@github.com:user/repo.git), here’s what actually happens:
- Git recognizes the URL as an SSH URL and hands the connection off to your system’s
sshclient rather than an HTTPS library. - The SSH client opens a connection to
github.comon port 22 (or port 443 if you’ve configured the SSH-over-HTTPS workaround for restrictive networks). - GitHub’s server presents its host key. Your client checks it against the fingerprint stored in
~/.ssh/known_hosts; on a first connection, you’re prompted to confirm and accept it. - Your client offers the public keys it has available, from
ssh-agentor the default files in~/.ssh/, and GitHub’s server issues a cryptographic challenge for each. - Your private key signs the challenge locally; the private key material itself is never sent over the network.
- GitHub verifies the signature against the public keys registered on every account, and identifies you as the owner of the first match.
- Once authenticated, the normal Git protocol takes over: for a push, your client sends the new objects (blobs, trees, commits) it computed locally, and asks GitHub to move the remote branch pointer to your new commit, provided it’s a fast-forward or you’re not blocked by branch protection rules.
Notice that steps 1 through 6 are entirely about proving identity; nothing about which branch you’re pushing, whether it’s a fast-forward, or what the commit contains is decided until step 7. This is why switching a remote from HTTPS to SSH, or back, never affects your commit history: it only changes the transport and authentication layer underneath.
Common Mistakes
Mistake 1: Uploading the private key instead of the public key
cat ~/.ssh/id_ed25519
Pasting the contents of id_ed25519, with no .pub extension, into GitHub’s “New SSH key” field will simply be rejected, but if you ever paste a private key into any web form by mistake, treat that key as compromised immediately: delete it, generate a new pair, and remove the old public key from every account it was added to. Only the file ending in .pub is meant to be shared.
Mistake 2: Wrong file permissions on the .ssh directory
ssh -T git@github.com
Output:
Load key "/home/you/.ssh/id_ed25519": bad permissions
git@github.com: Permission denied (publickey).
SSH refuses to use a private key that other users on the machine could read. Fix the permissions so only you can access the key files:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
Mistake 3: Cloning with HTTPS, then wondering why the SSH key isn’t used
An SSH key sitting in ~/.ssh/ has no effect on a repository whose remote URL starts with https://; Git only tries SSH when the remote URL itself uses the git@github.com:... or ssh:// form. Check with git remote -v and use git remote set-url, as shown in Example 3, if the protocol doesn’t match what you intended.
Mistake 4: One key shared across many machines
Copying the same private key file to a laptop, a desktop, and a CI server means revoking access from any one of them requires revoking it from all of them. Generate a separate key pair per device or CI system instead, and give each one a distinct -C comment and GitHub title so you can tell at a glance, under Settings → SSH and GPG keys, which key belongs to which machine.
Best Practices
- Use
ed25519keys for new setups; only fall back torsafor very old systems that lack ed25519 support. - Always set a passphrase on your private key, and let
ssh-agentor your OS keychain cache it so you’re not retyping it constantly. - Generate one key pair per device, with a descriptive
-Ccomment and matching GitHub key title, so old or lost devices can be revoked individually. - Use an SSH
configfile withHostaliases when you need multiple GitHub identities, such as personal and work accounts, on one machine, rather than reusing one key everywhere. - Review Settings → SSH and GPG keys periodically and delete keys for devices you no longer use.
- Never commit a private key file to a repository, and keep private key files out of any directory you track with Git.
- Prefer SSH URLs (
git@github.com:...) over HTTPS for day-to-day work once your key is set up; it avoids re-entering or refreshing a Personal Access Token.
Multiple GitHub accounts: SSH config example
If you use separate personal and work GitHub accounts, generate two key pairs and map each to a distinct host alias in ~/.ssh/config:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
Then clone using the alias instead of github.com directly:
git clone git@github-work:company/internal-tool.git
Git treats github-work purely as a name to look up in the SSH config; SSH resolves it to the right host and forces the matching identity file, so the two accounts never get crossed.
Practice Exercises
- Generate a new
ed25519SSH key with a passphrase, add it tossh-agent, upload the public key to your GitHub account, and confirm withssh -T git@github.comthat you see the “successfully authenticated” message. - Take a repository you currently have cloned over HTTPS and switch its
originremote to the SSH URL usinggit remote set-url, then verify the change withgit remote -vand confirm agit pullstill works without prompting for a token. - Set up two SSH key pairs and an
~/.ssh/configwith twoHostaliases, as shown in Best Practices, then clone the same repository twice, once through each alias, and confirm viagit remote -vin each clone that each points at a different host alias.
Summary
- SSH keys authenticate you to GitHub with a private/public key pair instead of a password or token; the private key never leaves your machine.
ssh-keygen -t ed25519 -C "<comment>"generates a new key pair; the.pubfile is what you upload to GitHub, never the private key.ssh-agentplusssh-addcaches your decrypted private key for a session so you aren’t prompted for a passphrase on every Git operation.ssh -T git@github.comis the standard way to confirm your key is registered and working before you rely on it.- SSH authentication is a transport-layer concern only; it has no effect on commit history, and switching a remote between HTTPS and SSH with
git remote set-urlchanges nothing about the repository’s objects. - Use one key per device, protect private keys with correct file permissions and a passphrase, and use SSH config
Hostaliases to manage multiple GitHub identities cleanly.
