I have 2 Github accounts: a personal one, and a professional one. If you have more than one account on Github, you've probably experienced this before:
ERROR: Permission to user2/repo.git denied to user1.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
To better understand what's going on, let's assume we have 2 users:
user1
is the main profile, associated with ~/.ssh/id_rsa
user2
is a secondary profile, associated with ~/.ssh/id_github_rsa
First, let's get some debugging info. In ~/.ssh/config
, add:
Host github.com
LogLevel DEBUG
Then try again a git push
in a repository owned by user2
:
debug1: Connecting to github.com [192.30.252.131] port 22.
debug1: Connection established.
[...]
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering RSA public key: ~/.ssh/id_rsa
[...]
debug1: Authentication succeeded (publickey).
The key used for authentication is id_rsa
attached to user1
. This is the problem. SSH tries keys in a certain order, and id_rsa
occurs first. The authentication succeeds at the SSH level (there IS a user attached to this key), but fails at the git level because user1
is not a member of the repository we are trying to push to, owned by user2
.
Now that we understand what the problem is, let's try to fix it.
Since SSH allows for custom configuration per host, the first idea that comes to mind is to create a special host with a preferred key. In ~/.ssh/config
, let's add a section for user2
:
Host github-user2
User git
Hostname github.com
IdentityFile ~/.ssh/id_github_rsa
We will also need to update our github repository. We need to change the current origin
from its default [email protected]
to github-user2
:
cd ~/projects/user2/project
git remote set-url origin github-user2:user2/project.git
Great! Let's try to push again:
ERROR: Permission to user2/project.git denied to user1.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Mmmm.. Looks like that didn't do it. Let's increase our log level to the maximum:
Host github-user2
LogLevel DEBUG3
User git
Hostname github.com
IdentityFile ~/.ssh/id_github_rsa
And push again:
debug2: ssh_connect: needpriv 0
debug1: Connecting to github.com [192.30.252.128] port 22.
debug1: Connection established.
[...]
debug2: key: ~/.ssh/id_rsa (0x700100200300),
debug2: key: ~/.ssh/id_github_rsa (0x700200300400), explicit
[...]
debug1: Next authentication method: publickey
debug1: Offering RSA public key: ~/.ssh/id_rsa
[...]
debug1: Authentication succeeded (publickey).
And so here is where weirdness happens: id_github_rsa
key seems to be recognized from our git config (marked as explicit
), but somehow id_rsa
is still used first. Why?
It took me a minute to figure this one out. I spent some time searching and eventually found
this blog post by Drew Crawford. The problem comes from the way IdentityFile
works. From the man:
Specifies a file from which the user's DSA, ECDSA or RSA authentication identity is read. The default is
~/.ssh/identity
for protocol version 1, and~/.ssh/id_dsa
,~/.ssh/id_ecdsa
and~/.ssh/id_rsa
for protocol version 2. Additionally, any identities represented by the authentication agent will be used for authentication. [...]
So despite specifying a preferred key for authentication, SSH will
first try keys already loaded in the agent. Since id_rsa
is our main key and we use it everywhere, chances are it's loaded in the agent first, therefore overriding our configuration.
With this new information in hand, let's update our SSH config.
So we need to tell SSH to ignore any keys already loaded in the agent, and just use the one we specify. Thankfully, there is an option for that, IdentitiesOnly
:
Specifies that ssh(1) should only use the authentication identity files configured in the ssh_config files, even if ssh-agent(1) or a PKCS11Provider offers more identities. The argument to this keyword must be
yes
orno
. This option is intended for situations where ssh-agent offers many different identities. The default isno
.
Let's update our ~/.ssh/config
:
Host github-user2
User git
Hostname github.com
IdentitiesOnly yes
IdentityFile ~/.ssh/id_github_rsa
And try one last push:
$ cd ~/projects/user2/project
$ git push
Everything up-to-date
Hooray \o/
So to successfully authenticate on Github with a secondary user, you need to:
IdentityFile
and IdentitiesOnly
origin
URL of every repo to use the SSH config: github-user:user/repo
Not that complicated, but not easy to figure out either. It certainly took me a minute, especially since my keys were not always loaded in the same order in the SSH agent, which confused things a bit. So I hope this will avoid you some headaches :)
That's it for today, cheers!