Skip to content

Instantly share code, notes, and snippets.

@interstella-5555
Last active April 1, 2026 17:56
Show Gist options
  • Select an option

  • Save interstella-5555/971f9111f58a67630e56d23e253814d9 to your computer and use it in GitHub Desktop.

Select an option

Save interstella-5555/971f9111f58a67630e56d23e253814d9 to your computer and use it in GitHub Desktop.
GitHub SSH + Commit Signing on macOS — single-account setup with macOS Keychain (zero prompts)

GitHub SSH + Commit Signing on macOS

One-time setup for SSH authentication and verified commit signing on GitHub. Keys on disk, passphrase in macOS Keychain — zero prompts after setup.

What you get:

  • git push / git pull via SSH (no HTTPS tokens)
  • All commits automatically signed ("Verified" badge on GitHub)
  • No prompts, no popups, no Touch ID — completely silent

Requirements: macOS, Git 2.34+


Step 1: Generate SSH key

ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/id_ed25519_github

You'll be asked to set a passphrase. This encrypts the private key file on disk — if someone copies the file, they can't use it without the passphrase.

Pick something short but not trivial (e.g. 3-4 random words). You'll type it one more time in Step 2, then never again.

Use the same email as your GitHub account (Settings → Emails). If you use GitHub's noreply email, use that: username@users.noreply.github.com.


Step 2: Store passphrase in macOS Keychain

ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github

Enter the same passphrase from Step 1. This stores it in macOS Keychain — from now on, the system unlocks the key automatically when you log into your Mac. No prompts, ever.

Verify the key is loaded:

ssh-add -l
# Should show your key fingerprint

Step 3: Configure SSH

File: ~/.ssh/config

If this file doesn't exist, create it. If it exists, add these lines at the top:

Host *
  AddKeysToAgent yes
  UseKeychain yes
  • AddKeysToAgent yes — automatically loads keys into the SSH agent
  • UseKeychain yes — reads passphrases from macOS Keychain (no prompts)

If you have other SSH keys (VPS, servers, other git hosting): these settings apply globally and won't break existing keys. They just enable Keychain integration for all keys.


Step 4: Configure Git

File: ~/.gitconfig

Add or update these settings:

[user]
    name = Your Name
    email = your-email@example.com
    signingkey = ~/.ssh/id_ed25519_github.pub
[gpg]
    format = ssh
[commit]
    gpgsign = true
[core]
    sshCommand = ssh -i ~/.ssh/id_ed25519_github -o IdentitiesOnly=yes

Important: user.email must match the email on your GitHub account — otherwise commits show as "Unverified".

How it works

  • gpg.format = ssh — use SSH keys for signing instead of GPG
  • commit.gpgsign = true — sign every commit automatically
  • signingkey — points to the .pub file; ssh-keygen reads it for signing
  • core.sshCommand — tells git which private key to use for push/pull
  • -o IdentitiesOnly=yes — prevents the SSH agent from offering other keys

Why two different key paths? sshCommand uses the private key (id_ed25519_github) because SSH needs it for authentication. signingkey uses the public key (.pub) because ssh-keygen -Y sign identifies the key by its public half.


Step 5: Add key to GitHub

Copy the public key:

cat ~/.ssh/id_ed25519_github.pub | pbcopy

Then go to github.com/settings/ssh/new and add it twice:

  1. Authentication Key — for push/pull/clone
  2. Signing Key — for verified commits

Same key, two entries. Both are required.


Step 6: Fix existing remotes (optional)

If your repos use HTTPS URLs, switch them to SSH. New clones via git clone git@github.com:... already use SSH — this is only for existing repos.

# Check current remote
git remote get-url origin
# If it shows https://github.com/... → fix it:

git remote set-url origin git@github.com:username/repo.git

Bulk fix all repos in a directory (change ~/code/ to your path):

for dir in ~/code/*/; do
  [ -d "$dir/.git" ] || continue
  url=$(git -C "$dir" remote get-url origin 2>/dev/null)
  if echo "$url" | grep -q "https://github.com/"; then
    new_url=$(echo "$url" | sed 's|https://github.com/|git@github.com:|')
    git -C "$dir" remote set-url origin "$new_url"
    echo "Fixed: $(basename $dir)"
  fi
done

Step 7: Verify

# Test SSH auth (should show your GitHub username — no prompts)
ssh -i ~/.ssh/id_ed25519_github -o IdentitiesOnly=yes -T git@github.com
# → Hi username! You've successfully authenticated...

# Test commit signing on a throwaway branch
cd ~/code/some-repo
git checkout -b test-signing
git commit --allow-empty -m "test signing"
git log --show-signature -1
# → Good "git" signature with ED25519 key...

# Push and check the "Verified" badge on GitHub
git push -u origin test-signing
open "$(git remote get-url origin | sed 's|git@github.com:|https://github.com/|;s|\.git$||')/commits/test-signing"

Clean up — delete the test branch locally and on GitHub:

git checkout main
git branch -D test-signing
git push origin --delete test-signing

Troubleshooting

"Permission denied (publickey)"

  1. Check agent has key: ssh-add -l
  2. If empty: ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github
  3. Check correct key is offered: GIT_SSH_COMMAND="ssh -v" git fetch 2>&1 | grep Offering
  4. Check key is on GitHub as Authentication Key

Commit shows "Unverified" on GitHub

  1. Check key is on GitHub as Signing Key (not just Authentication)
  2. Check email matches: git config user.email must match your GitHub account email
  3. Check signingkey points to existing file: ls $(git config user.signingkey)
  4. Test locally: git log --show-signature -1

Agent loses keys after restart

  1. Check ~/.ssh/config has both AddKeysToAgent yes and UseKeychain yes
  2. Re-add: ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github

Optional: Clean up old signing setup

If you previously used GPG for commit signing:

  • brew uninstall gnupg — remove GnuPG
  • rm -rf ~/.gnupg — remove GPG keyring
  • Remove GPG_TTY from ~/.zshrc
  • Remove old GPG keys from github.com/settings/keys

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment