Time Based One-Time Passwords, with Vault

Yiğit İrez
4 min readDec 28, 2021

Everyone uses an authenticator app these days. Well, vault can provide the same service for your apps. Let’s create our own 2FA for our apps and see how convenient it is.

Goal: QR code, readable from an authenticator app and checking if its valid.

What we need

  • Vault, somewhere (I’m using local)
  • Some sort of authenticator for the Time-Based One-Time Passwords (ToTP) Engine. I used Authy but any will work. Chrome authenticator addon from here is also good enough.
  • Postman or bash is good enough

Let’s start by enabling the secrets engine for Time Based One-time Password (totp from now on).

activate the engine

You can type any path below, I forgot and left it default. Anywhere in the endpoints where it says totp will need to change to the root path you write.

basic config

While testing I came across an error when I selected my issuer in the below command with “-” character at the end by mistake. Read more about it here. Apparently Vault does not allow an issuer to have such a char in the end. ALSO Vault gives the same error if you are trying to access the wrong endpoint.

vault write --field=barcode totp/keys/test1 random_stuff=123 generate=true account_name=yigit issuer=my-super-vault-
wonderfully clear error message
vault write --field=barcode totp/keys/test1 random_stuff=123 generate=true account_name=yigit issuer=mysupervault

In the above command, the field=barcode allows us to only retrieve the base64 PNG data to create our QR code (we also get the url to auth if not). generate=true means we want to create a new one, account_name is another necessary part which can be your name (or anything you want) and the issuer can be anything we want but it is mandatory. The only extra data there is the random_stuff=123 key-value pair. test1 is our key name

wall of text (basically a base64 encoded QR code)

If we were to decode this we would get,

Let’s pass this stuff to a PNG file and see what happens. The command itself is still the same except we added base64 conversion, and stuffing the result to a file. We could also manually save the result to a file and convert that as well.

vault write --field=barcode totp/keys/test1 random_stuff=123 generate=true account_name=yigit issuer=mysupervault | base64 -d > qr2.jpg
our very own qr code

Now let’s try to use an authenticator to see if it works. I used authy and could create codes but authy didn’t allow screenshots so instead I’m opting with chrome authenticator addon from here. If we scan the QR with the authenticator, we should get yigit account added successfully.

well
looks very plain but it is working

Just go ahead and try reading the contents of the qr. What you get is a URL like below.

otpauth://totp/mysupervault:yigit?algorithm=SHA1&digits=6&issuer=mysupervault&period=30&secret=4K6XE7CQOZWNYOBRS4AEVCCSBNQRO5WF

We can also get this number from an app as below. We will be using the endpoint v1/totp/code/test1. totp is the root path we gave for our engine, test1 is the keyname we used throughout. Don’t mistake with mysupervault which is the issuer, like github.

Postman has an env var capability but it doesn’t use the one from the host but keeps a set for itself. Click the eye on the top right, and create your env vars. Then after you select the active environment (super env) you can your vars as {{name_of_var}}

l33t postman usage (not)

Ignore the request body, GET method is enough.

noice

Now let’s check if the number we got is valid. Same endpoint as before and in the request body we will be sending just the code.

Noice

Thanks for reading and see you next time.

--

--

Yiğit İrez

Let’s talk devops, automation and architectures, everyday, all day long. https://www.linkedin.com/in/yigitirez/