devAlice
← Mac

Multiple GitHub Accounts via SSH on Mac — Manage Work + Personal Keys

The straightforward way to cleanly separate multiple hosts/accounts (work GitHub, personal GitHub, external clients) with ~/.ssh/config.

Running a work GitHub account and a personal GitHub account on the same machine breaks things on day one — git push goes to the wrong account, freshly cloned repos refuse with permission denied, gh CLI keeps signing into the same account. This guide is the straightforward way to separate accounts/hosts via ~/.ssh/config on macOS 14+ / OpenSSH 9.x.

A follow-up to Mac initial setup, where you created one ed25519 key. Extends to GitLab/Bitbucket for external clients as well.

TL;DR

  1. Create a separate SSH key per account (ed25519) with distinct file names
  2. In ~/.ssh/config, set per-host IdentityFile + Host aliases explicitly
  3. Use aliases in clone URLs: git@github-work:user/repo.git instead of git@github.com:...
  4. Auto-branch user.email per working directory with .gitconfig includeIf
  5. gh CLI 1.x+ supports multiple simultaneous accounts

Prerequisites

  • macOS 14+, OpenSSH 9.x (ssh -V)
  • A GitHub/GitLab account for each persona
  • An existing single-key setup from Mac initial setup or equivalent

1. Per-Account SSH Keys — 5 min

Use intentionally distinct filenames.

# Work account
ssh-keygen -t ed25519 -C "work@example.com" -f ~/.ssh/id_ed25519_work
 
# Personal account
ssh-keygen -t ed25519 -C "personal@example.com" -f ~/.ssh/id_ed25519_personal
 
# External client (optional)
ssh-keygen -t ed25519 -C "client-foo@example.com" -f ~/.ssh/id_ed25519_client

Register only the public key on each GitHub/GitLab account:

pbcopy < ~/.ssh/id_ed25519_work.pub       # work GitHub
pbcopy < ~/.ssh/id_ed25519_personal.pub   # personal GitHub

In a browser, visit https://github.com/settings/ssh/new, sign in as each account, paste, save.

💡 GitHub rejects re-using the same key on two accounts ("Key is already in use"). Hence the per-account key split is mandatory.


2. Author ~/.ssh/config — 10 min

Split with host aliases. Integrates with macOS Keychain + Touch ID extensions.

# ~/.ssh/config
 
# Work GitHub
Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work
  IdentitiesOnly yes
  AddKeysToAgent yes
  UseKeychain yes
 
# Personal GitHub
Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_personal
  IdentitiesOnly yes
  AddKeysToAgent yes
  UseKeychain yes
 
# Client GitLab
Host gitlab-client
  HostName gitlab.com
  User git
  IdentityFile ~/.ssh/id_ed25519_client
  IdentitiesOnly yes
  AddKeysToAgent yes
  UseKeychain yes

Key options:

  • IdentitiesOnly yes — even if the agent holds other keys, only the explicit one is used. Without it, the wrong key is tried first and GitHub returns 403.
  • AddKeysToAgent yes + UseKeychain yes — macOS Keychain integration. Passphrase entered once, never again.

Add Keys to the SSH Agent

ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_personal
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_client

Verification

ssh -T git@github-work
# Hi work-username! You've successfully authenticated...
 
ssh -T git@github-personal
# Hi personal-username! You've successfully authenticated...

If you're greeted as the wrong account, see §3 / troubleshooting.


3. Use Aliases in Clone URLs — the Daily Pattern

Work repo:

# Vanilla GitHub URL — IdentitiesOnly does branch, but explicit alias is cleaner
git clone git@github.com:org/repo.git  # IdentitiesOnly + first match — ambiguous
 
# Use alias — explicit
git clone git@github-work:org/repo.git

Personal repo:

git clone git@github-personal:me/myrepo.git

Already-cloned repos: change the remote.

cd ~/work/repo
git remote set-url origin git@github-work:org/repo.git
 
cd ~/personal/myrepo
git remote set-url origin git@github-personal:me/myrepo.git

Verify with git remote -v.


4. Auto-Branch user.emailincludeIf — 5 min

Branch git config user.email by folder location. Forces work-folder commits to use work email, personal folder to use personal email.

Main ~/.gitconfig

[user]
  name = Your Name
  # Leave default email blank or use the most common one
 
[includeIf "gitdir:~/work/"]
  path = ~/.gitconfig-work
 
[includeIf "gitdir:~/personal/"]
  path = ~/.gitconfig-personal

⚠️ The path after gitdir: must end with a slash. ~/work is wrong, ~/work/ is correct.

~/.gitconfig-work

[user]
  email = you@company.com
  name = Your Name (Company)
 
[commit]
  gpgsign = true   # if work policy requires signed commits
 
[gpg]
  format = ssh
 
[gpg "ssh"]
  defaultKeyCommand = ssh-add -L
  program = ssh-keygen

~/.gitconfig-personal

[user]
  email = you@personal.com
  name = Your Name

Verification

cd ~/work/some-repo
git config user.email
# you@company.com
 
cd ~/personal/some-repo
git config user.email
# you@personal.com

Auto-branching works. Wrong-email commits are now structurally prevented.


5. gh CLI Multi-Account — Simultaneous Auth

gh 2.40+ supports multi-account. You can be signed into work and personal GitHub.com simultaneously from the same machine.

Add Auth

# First account (skip if already signed in)
gh auth login
 
# Second account
gh auth login    # sign in as a different GitHub.com account

Switch Active Account

gh auth status
# Lists all signed-in accounts and the active one
 
gh auth switch
# Interactive — pick another account
 
gh auth switch -u personal-username

Per-Repo Active Account (optional)

# In a work repo, activate the work account
cd ~/work/repo
gh auth switch -u work-username

gh commands use the active account. SSH is branched by config in §2, so no conflict.


6. Common Sticking Points

6.1 Personal Access Token (PAT) Conflicts

If you chose HTTPS in gh auth login, the PAT is stored in OS Keychain. Wrong PAT being used for other accounts:

gh auth status                    # which PAT is stored where
security find-internet-password -s github.com -a "your-username"
security delete-internet-password -s github.com -a "wrong-username"
gh auth login                      # re-authenticate

6.2 Same Organization Accessed by Both Accounts

If your personal account is also a collaborator on the work GitHub org, clone URLs become ambiguous:

# Use explicit aliases
git clone git@github-work:org/shared-repo.git work-side
git clone git@github-personal:org/shared-repo.git personal-side

Putting them in separate directories splits user.email + key choices.

6.3 macOS Keychain Forgets Passphrase

UseKeychain yes in ~/.ssh/config is ignored on some macOS 15+ setups. Workaround:

# Explicitly start ssh-agent + add key
eval "$(ssh-agent -s)"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work

You can add the auto-register snippet to .zshrc if needed.


7. Security Checklist

  • Never share private keys — only .pub is registered
  • Use a passphrase — encrypts the key file. macOS Keychain caches after one entry
  • Separate work/personal keys — limits blast radius if one leaks
  • ~/.ssh/config permschmod 600 ~/.ssh/config
  • ~/.ssh dir permschmod 700 ~/.ssh
  • Hardware keys (optional) — YubiKey + FIDO2 via ssh-keygen -t ed25519-sk (separate guide)

8. Troubleshooting

Permission denied (publickey) despite explicit key

IdentitiesOnly yes is missing — the agent's other keys are tried first and denied. Add to config.

ssh -vT git@github-work 2>&1 | grep -E "(Offering|identity file)"

If multiple keys are tried, IdentitiesOnly yes is missing.

Greeted as the wrong account

ssh -T git@github-work returns the personal account. Causes:

  • Wrong key prioritized in the ssh-agent
  • Block order or typo in ~/.ssh/config's Host github-work / IdentityFile
ssh-add -L                          # which keys are in the agent
ssh-add -D                          # clear all
ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work
ssh -T git@github-work

git push goes to personal

URL is git@github.com:org/repo.git and the personal key wins in the agent. Change the URL.

git remote set-url origin git@github-work:org/repo.git

includeIf doesn't fire

  • Trailing slash missing on the path (~/work ❌, ~/work/ ✅)
  • Folder is a symlink — OS-dependent. Use the real path.

gh auth switch not available

gh is older than 2.40. Upgrade:

brew upgrade gh
gh --version

Next Steps

References

Changelog

  • 2026-05-12 — Initial draft (devAlice M3 seed expansion)

Comments