NimbleTOTP (NimbleTOTP v0.1.2) View Source
NimbleTOTP is a tiny library for Two-factor authentication (2FA) that allows developers to implement Time-Based One-Time Passwords (TOTP) for their applications.
Two-factor authentication (2FA)
The concept of 2FA is quite simple. It's an extra layer of security that demands a user to provide two pieces of evidence (factors) to the authentication system before access can be granted.
One way to implement 2FA is to generate a random secret for the user and whenever the system needs to perform a critical action it will ask the user to enter a validation code. This validation code is a Time-Based One-Time Password (TOTP) based on the user's secret and can be provided by an authentication app like Google Authenticator or Authy, which should be previously installed and configured on a compatible device, e.g. a smartphone.
Note: A critical action can mean different things depending on the application. For instance, while in a banking system the login itself is already considered a critical action, in other systems a user may be allowed to log in using just the password and only when trying to update critical data (e.g. its profile) 2FA will be required.
Using NimbleTOTP
In order to allow developers to implement 2FA, NimbleTOTP provides functions to:
- Generate secrets composed of random bytes.
- Generate URIs to be encoded in a QR Code.
- Generate Time-Based One-Time Passwords based on a secret.
Generating the secret
The first step to set up 2FA for a user is to generate (and later persist) its random
secret. You can achieve that using NimbleTOTP.secret/1
.
Example:
secret = NimbleTOTP.secret()
#=> <<178, 117, 46, 7, 172, 202, 108, 127, 186, 180, ...>>
By default, a binary with 20 random bytes is generated per the HOTP RFC.
Generating URIs for QR Code
Before persisting the secret, you need to make sure the user has already configured the authentication app in a compatible device. The most common way to do that is to generate a QR Code that can be read by the app.
You can use NimbleTOTP.otpauth_uri/3
along with
eqrcode to generate the QR
code as SVG.
Example:
uri = NimbleTOTP.otpauth_uri("Acme:alice", secret, issuer: "Acme")
#=> "otpauth://totp/Acme:alice?secret=MFRGGZA&issuer=Acme"
uri |> EQRCode.encode() |> EQRCode.svg()
#=> "<?xml version=\\"1.0\\" standalone=\\"yes\\"?>\\n<svg version=\\"1.1\\" ...
Generating a Time-Based One-Time Password
After successfully reading the QR Code, the app will start generating a
different 6 digit code every 30s
. You can compute the verification code
with:
NimbleTOTP.verification_code(secret)
#=> "569777"
The code can be validated using the valid?/3
function. Example:
NimbleTOTP.valid?(secret, "569777")
#=> true
NimbleTOTP.valid?(secret, "012345")
#=> false
After validating the code, you can finally persist the user's secret so you use it later whenever you need to authorize any critical action using 2FA.
Link to this section Summary
Functions
Generate the uri to be encoded in the QR code.
Generate a binary composed of random bytes.
Checks if the given otp
code matches the secret.
Generate Time-Based One-Time Password.
Link to this section Functions
Generate the uri to be encoded in the QR code.
Examples
iex> NimbleTOTP.otpauth_uri("Acme:alice", "abcd", issuer: "Acme")
"otpauth://totp/Acme:alice?secret=MFRGGZA&issuer=Acme"
Generate a binary composed of random bytes.
The number of bytes is defined by the size
argument. Default is 20
per the
HOTP RFC.
Examples
NimbleTOTP.secret()
#=> <<178, 117, 46, 7, 172, 202, 108, 127, 186, 180, ...>>
Checks if the given otp
code matches the secret.
It accepts the same options as verification_code/2
.
Generate Time-Based One-Time Password.
Options
- :time - The time in unix format to be used. Default is
System.os_time(:second)
- :period - The period (in seconds) in which the code is valid. Default is
30
.
Examples
NimbleTOTP.verification_code(secret)
#=> "569777"