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 🚀
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 😀
Top comments (1)