01 · THE CHOICE
Three ways to authenticate, and when each is right.
| Method | How it works | Best for | Watch out for |
|---|---|---|---|
| SSH keys | A key pair per machine; the public half lives on your account | Your own machines, long-lived setups, servers | Blocked outbound on some corporate networks, though port 443 works around it |
| HTTPS with a token | A personal access token stored in a credential helper | Restricted networks, CI, short-lived access | Tokens expire, and scopes are easy to over-grant |
| GitHub CLI | Browser sign-in that configures Git for you | Getting productive in two minutes | You still want a key for servers and automation |
The pragmatic answer for a personal machine is SSH. There is nothing to expire, nothing to paste, and revoking access to one machine is a single click that does not affect anything else.
02 · THE KEY
One ed25519 key, per machine, with a passphrase.
# The comment identifies the machine, not you. It appears in GitHub.
ssh-keygen -t ed25519 -C "desktop-windows-2026"
# Start the agent and load the key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Copy the PUBLIC half into GitHub, Settings, SSH and GPG keys
cat ~/.ssh/id_ed25519.pub
# Confirm it works
ssh -T git@github.com
On Windows, PowerShell has OpenSSH built in. Start the agent as a service once and it will hold your key across sessions:
Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Four rules worth following
- ed25519, not RSA. Shorter, faster and the current default. Use RSA only for a system that genuinely cannot accept anything else.
- Set a passphrase. The agent means you type it once per session. A key without one is a plaintext credential in a predictable location.
- One key per machine. Copying a key between computers means you can never revoke one without breaking the others.
- Never commit a private key. Automated scanners find them within minutes of a push, including in a repository you later make private.
If SSH is blocked on your network, GitHub accepts SSH over port 443. Add a host entry for ssh.github.com on port 443 in your SSH config and it behaves identically.
03 · MULTIPLE ACCOUNTS
Work and personal on one machine, without confusion.
The reliable approach is one key per account plus SSH host aliases, so the remote URL itself selects the identity.
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
# Clone through the alias to use the work identity
git clone git@github-work:company/project.git
# Fix an existing repository
git remote set-url origin git@github-work:company/project.git
git remote -v
IdentitiesOnly yes matters more than it looks: without it, the agent offers every loaded key in turn, and the server accepts the first one that works — which may not be the account you intended.
Getting the commit author right too
[user]
name = Your Name
email = personal@example.com
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
Every repository under ~/work/ then picks up the work name and email automatically. This prevents the other half of the problem: correct authentication with the wrong author on the commit.
04 · SIGNING
Sign with the SSH key you already have.
Commit signing proves a commit came from you rather than from anyone who can set a name and email — which is anyone. Modern Git can sign with an SSH key, so there is no reason to set up GPG unless you already use it.
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Verify locally
git log --show-signature -1
Then add the same public key a second time in your GitHub settings, with the type set to Signing Key rather than Authentication Key. One key, two registrations, two purposes. Commits then show the verified badge.
- Enable vigilant mode in your GitHub settings once every machine signs. Unsigned commits attributed to you are then flagged as unverified rather than silently trusted.
- Register every machine’s key as a signing key, or commits from the others will show as unverified.
- Web edits sign automatically with GitHub’s own key, which is expected and fine.
Signing is not a formality on a public repository. Anyone can author a commit under your name and email. The signature is the only thing that distinguishes your work from an impersonation of it.
05 · TOKENS
When you do need a token, scope it narrowly.
Automation and restricted networks still need HTTPS with a token. The failure mode there is not leakage so much as over-permission.
- Prefer fine-grained tokens. They target specific repositories with specific permissions, instead of granting a scope across everything you can see.
- Set an expiry. A token that never expires is a permanent credential you will forget about. Ninety days is a reasonable default.
- One token per purpose. Separate tokens for CI, a local script and a deployment mean you can revoke one without an outage everywhere else.
- Never put a token in a URL. It ends up in shell history, in logs, and in the repository configuration file.
- Use the credential manager. Git Credential Manager on Windows stores tokens in the OS credential store rather than in a plaintext file.
- In CI, use the provided identity. GitHub Actions supplies a scoped token for the workflow run; a long-lived personal token is a downgrade in both security and convenience.
06 · ROTATION
The five minutes after a credential is exposed.
Committed a private key, pushed a token, or lost a laptop. In that order, immediately:
Delete the key or token in GitHub settings before anything else. Cleaning history while the credential is still valid is the wrong order.
New key pair, new passphrase, registered for both authentication and signing.
Review security log, active sessions, authorised applications and deploy keys. Look for anything you did not create.
Rewrite it out of the repository, force-push, and ask GitHub support to expire cached views of the old objects.
Treat any exposed secret as compromised, permanently. Public repositories are scanned continuously by automated systems; a key pushed and deleted a minute later has been collected. Rotate it rather than hoping.
Routine hygiene
- Review your registered SSH keys twice a year and remove machines you no longer own.
- Give each key a comment that identifies the machine, so the list is meaningful later.
- Enable secret scanning and push protection on repositories that accept contributions.
- Keep two-factor recovery codes somewhere that does not depend on the account they protect.
07 · QUICK ANSWERS
GitHub authentication, briefly.
SSH for your own machines: nothing expires, nothing gets pasted, and revoking one machine does not affect the others. HTTPS with a token is better on restricted networks where outbound SSH is blocked, and in automation. If SSH is blocked, GitHub also accepts SSH over port 443.
ed25519. It is shorter, faster and the current default, and GitHub has supported it for years. Use RSA with at least 4096 bits only when you need to talk to a system that genuinely cannot accept ed25519. Always set a passphrase and let the SSH agent hold it for the session.
Create a separate key per account, define a host alias for each in your SSH config with IdentitiesOnly set to yes, and clone through the alias. Add a conditional include in your global Git config so repositories under a work directory automatically use the work name and email on commits.
Configure Git to sign with SSH: set gpg.format to ssh, point user.signingkey at your public key, and enable commit.gpgsign. Then add the same public key to GitHub a second time with the type set to Signing Key. Register every machine key you use, or commits from the others will show as unverified.
Revoke it in GitHub settings immediately, before cleaning anything. Generate a replacement, review your account security log, active sessions, authorised applications and deploy keys, and only then rewrite the repository history. Assume the exposed key was collected by automated scanners regardless of how quickly you deleted it.