Get 2FA Codes From The Terminal
Tags: 2fa, totp, security, github
Published: 2020-01-21 12:32:12

Afraid of losing those backup codes you printed? I surely was, until I found a way to get those 2fa numbers from a terminal, which is perfect for my use case.

`tl;dr` skip to `Nuff said how to do this?` section

# Intro

2fa is not very complicated. There's basically a secret, a string, that gets stored in the app. It's in the Qr code. Then the app uses a standard time-based algorithm to generate codes.

These days it's very common to use 2fa on popular services like github, your org may even required it. Usually it goes like this:

- enable 2fa on the account
- they give you recovery codes to print
- scan Qr code with app
- app now generates codes that last around 30s
- to login you use password and a code

Pretty safe right? Let's look at some ways a regular human could mess this up:

- losing the phone with the app
- not printing backup codes
- losing the backup codes
- phone is not reachable, not charged or dead
- backup codes could be leaked
- risk losing github if losing a piece of paper

I feel that it's quite possible for a person to mess it up and get locked out. One of the ways to avoid it is having an extra device that generates codes. This is not easy because:

- most 2fa apps known are mobile apps, so you'd need another phone
- the Qr code hides the secret from you so you can't setup a second phone

We'll work around these problems shortly.

# Security Considerations

Before we look into setting up a CLI to do this, some points:

- having a second device generating 2fa codes is less safe

Compared to the chances of some human error around 2fa I think this risk is fine. The main problem I'm trying to avoid is getting myself locked out for some random reason like not finding the backup codes. Also, the second device would be a CLI on a computer, which does have it's own safety mechanisms, such as hard drive encryption and login passwords. It's also less likely to lose or steal a computer than a mobile device.

- the method we'll use requires de 2fa secret as input

So this secret would exist in your filesystem at some point, probably in plain text. Consider that if you downloaded a copy of the backup codes and left them in your computer, that's way more risky than doing this, because backup codes are much easier to use. We can mitigate this risk with OS level and filesystem level security though.

Generally speaking, I think having two 2fa devices for the same account is a great idea for the average 2fa user. **It may not be a good idea for use cases where maximum security is required**. I've **never** seen a friend's account with 2fa hacked, but I've seen **two** friends mess up and lose access to their github for silly reasons. So,

# Nuff said how to do this?

- Setup some new account with 2fa, when you get to the Qr code, stop.

We need to have access to the 2fa secret which is not normally exposed to the user, except during setup.

- If you can get the secret in plain text, do that.

Github exposes a link to the secret if you can't use a Qr code at the time.

- If you can't and you're stuck with the Qr code, download a Qr code reader.

Don't use your 2fa app! It won't tell you the secret. The Qr code app should just decode the information and show you. Prefer the simplest app you can find and erase its history when you get the secret string. If paranoid do it while offline and uninstall the app after each scan.

The secret may be in a URL like format, for instance:

`oauth:blablablasecret=foobar&issuer=Github`

you want only the `foobar` string.

- Download a software package for your system called `oath-toolkit`

If you're on linux you know how to do this, on mac you can use brew. If you installed successfully, `which oathtool` should print output.

- Save the secret somewhere.

```
# for example
mkdir ~/.private
echo -n "paste secret here" > ~/.private/github.2fa
chmod 600 ~/.private/github.2fa
```

Make sure you don't commit this folder, ever.

- Generate a code :rocket:

```
oathtool -b --totp "$(cat ~/.private/github.2fa)"
# prints 882140
```

All done now.

### Finally

You may need to redo the setup for accounts you already have 2fa on to use this method.

Have a great day now 😀