[38;5;244m┌─[0m [38;5;40mroot@joaocosta:~#[0m [38;5;245mcat posts/6.md[0m [38;5;244m────────────────────────────────────────────[0m

[38;5;40m#[0m [1mGithub, ssh keys and 2FA[0m
[38;5;245mpublished 2020-09-03 · 4 min read · https://joaocosta.dev/blog/6[0m

I recently found myself setting up 2FA on my GitHub account and for that I
started using the [1mssh protocol[0m instead of the default [1mhttps protocol[0m. This is a
quick guide explaining how and why you'd want to do that too.

[38;5;38m##[0m [1mIntroduction[0m

I have a little project going on where I use a [38;5;40mraspberry pi zero[0m
[38;5;244m(https://www.raspberrypi.org/blog/raspberry-pi-zero/)[0m as a dedicated password
manager. It could more accurately be described as a secrets keeper/manager, but
I use it mostly for passwords. Anyway, I wanted to set up 2FA for as many
services as I could (I'm currently using [38;5;40mFreeOTP+[0m
[38;5;244m(https://f-droid.org/en/packages/org.liberty.android.freeotpplus/)[0m on android
and it has everything I need/want), so I started setting them up. Both my
raspberry pi and my android have the OTPs for redundancy.

At some point, I set up [38;5;40m2FA on my Github account[0m
[38;5;244m(https://help.github.com/en/github/authenticating-to-github/securing-your-account-with-two-factor-authentication-2fa)[0m
and all seemed well, until I tried pushing to one of my GitHub repositories from
the command line.

[38;5;38m##[0m [1m2FA and the command line[0m

It seems like 2FA and git from the command line don't play well together. For
example, if you try to clone a private repository, your credentials will not be
accepted. You'll get an "invalid username or password" error message. This
happens because GitHub uses the [1mhttps protocol[0m by default and recommends it for
its users, because it usually works [3mout of the box[0m.

If you want to use 2FA (you should) with git on the command line, you'll have to
use one of these solutions.

[38;5;135m###[0m [1mSolution 1: Create a personal access token[0m

You should do this if you intend to keep using the [1mhttps protocol[0m for your
GitHub operations. GitHub has a nice step-by-step [38;5;40mguide[0m
[38;5;244m(https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)[0m
on their help page explaining how to do this, but the tl;dr is:

[38;5;40m→[0m Go to your account settings;
[38;5;40m→[0m Go to the [1mDeveloper settings[0m tab;
[38;5;40m→[0m Go to the [1mPersonal access tokens[0m tab;
[38;5;40m→[0m Press the [1mGenerate new token[0m button;
[38;5;40m→[0m Give it a name and the permissions you want/need (e.g.: repo);
[38;5;40m→[0m Copy the token and keep it safe like you would for your password (the token
  isn't recoverable).

Now to use the token, you just need to provide it during the authentication
process instead of your password.

I don't like this solution because you have to keep track of 2 different
passwords (more vulnerable) and this new [3m"token password"[0m defeats the purpose of
2FA (since it bypasses the 2FA temporary code). You can mitigate these problems
by limiting how much [3mpower[0m the access token has (give it fewer permissions), but
it still isn't optimal.

[38;5;135m###[0m [1mSolution 2: Use the [1mssh protocol[0m[0m

To use the [1mssh protocol[0m, you'll need an [1mssh key pair[0m. While browsing the web, I
came across this amazing [38;5;40mtutorial[0m [38;5;244m(https://happygitwithr.com/ssh-keys.html)[0m,
which helped me understand the subject better and quickly set everything up
correctly.

I advise you to read it, but if you're in a hurry and on Linux, you can just
copy the commands below (which were taken from the tutorial linked above) and
follow the on-screen instructions:

[38;5;244m┄──────────────────────────────────────────────────────────────────────── bash [0m
[38;5;245m│[0m # this will ask for a filename and an optional passphrase for the key (you should
[38;5;245m│[0m # provide it one)
[38;5;245m│[0m ssh-keygen -t rsa -b 4096 -C "USEFUL-COMMENT"
[38;5;245m│[0m 
[38;5;245m│[0m # this makes sure the ssh-agent is running
[38;5;245m│[0m eval "$(ssh-agent -s)"
[38;5;245m│[0m # add your key to the ssh-agent (change the path to the key if you didn't use
[38;5;245m│[0m # the default)
[38;5;245m│[0m ssh-add ~/.ssh/id_rsa
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

After generating your key, you just need to associate the generated public key
with your GitHub account. To do this, you need to go to your GitHub account
settings, access the [1mSSH and GPG keys[0m tab, and copy the contents of your public
key to a new [1mssh key[0m, e.g. using: [38;5;38mxclip -sel clip < ~/.ssh/id_rsa.pub[0m to insert
the key contents into your clipboard.

Now that you have associated your [1mssh key[0m with your account, you just need to
start using the [1mssh protocol[0m versions of your remote links.

Imagine you have the following repository:
[38;5;38mhttps://github.com/leereilly/games.git[0m. It is using the [1mhttps protocol[0m. The
equivalent [1mssh protocol[0m link is: [38;5;38mgit@github.com:leereilly/games.git[0m. As you can
see, it is really easy to convert from one [1mprotocol[0m to another. I even found a
[38;5;40msmall bash script[0m [38;5;244m(https://gist.github.com/m14t/3056747)[0m to make the conversion
of your repository's remotes to the [1mssh protocol[0m.

[38;5;244m┄──────────────────────────────────────────────────────────────────────── bash [0m
[38;5;245m│[0m #/bin/bash
[38;5;245m│[0m #-- Script to automate https://help.github.com/articles/why-is-git-always-asking-for-my-password
[38;5;245m│[0m 
[38;5;245m│[0m REPO_URL="$(git remote -v | grep -m1 '^origin' | sed -Ene's#.*(https://[^[:space:]]*).*#\1#p')"
[38;5;245m│[0m if [ -z "$REPO_URL" ]; then
[38;5;245m│[0m   echo "-- ERROR:  Could not identify Repo url."
[38;5;245m│[0m   echo "   It is possible this repo is already using SSH instead of HTTPS."
[38;5;245m│[0m   exit
[38;5;245m│[0m fi
[38;5;245m│[0m 
[38;5;245m│[0m USER="$(echo $REPO_URL | sed -Ene's#https://github.com/([^/]*)/(.*).git#\1#p')"
[38;5;245m│[0m if [ -z "$USER" ]; then
[38;5;245m│[0m   echo "-- ERROR:  Could not identify User."
[38;5;245m│[0m   exit
[38;5;245m│[0m fi
[38;5;245m│[0m 
[38;5;245m│[0m REPO="$(echo $REPO_URL | sed -Ene's#https://github.com/([^/]*)/(.*).git#\2#p')"
[38;5;245m│[0m if [ -z "$REPO" ]; then
[38;5;245m│[0m   echo "-- ERROR:  Could not identify Repo."
[38;5;245m│[0m   exit
[38;5;245m│[0m fi
[38;5;245m│[0m 
[38;5;245m│[0m NEW_URL="git@github.com:$USER/$REPO.git"
[38;5;245m│[0m echo "Changing repo url from "
[38;5;245m│[0m echo "  '$REPO_URL'"
[38;5;245m│[0m echo "      to "
[38;5;245m│[0m echo "  '$NEW_URL'"
[38;5;245m│[0m echo ""
[38;5;245m│[0m 
[38;5;245m│[0m git remote set-url origin "$NEW_URL"
[38;5;245m│[0m 
[38;5;245m│[0m echo "Success"
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

This is the solution that I went with. I believe the only problem you can have
while using the [1mssh protocol[0m is having the connection to port 22 (ssh port)
blocked is in your network. I've never had that problem, but GitHub suggests
that you may still be able to [38;5;40muse [1mssh[0m over the [1mhttps[0m port[0m
[38;5;244m(https://help.github.com/en/github/authenticating-to-github/using-ssh-over-the-https-port)[0m
if you ever find yourself in such a situation.

[38;5;38m##[0m [1mConclusions[0m

This was mostly a quick PSA to get more people to use the [1mssh protocol[0m and 2FA
on github. It's easy and it'll keep your accounts more secure. Stay safe :P

[38;5;244m└─[0m [38;5;40m→[0m view online: [38;5;40mhttps://joaocosta.dev/blog/6[0m
