Two-Factor authentication is a good way of increasing login security in systems, and is now quite widespread: it’s the six digit number that rolls over every 30 seconds. It’s designed to be very simple to operate as a user, but how much effort is involved as a developer?
How 2FA works
There’s a couple of different methods for multi-factor authentication; I’ll be looking at the Time-based One-Time Password algorithm (TOTP).
As it turns out, it’s quite straight-forward to get started with. On the server side, a secret key is generated and stored, then sent to the user (typically as a QR code or a hex string). This is a shared secret.
When the user wants to login, the server asks for their code. The user generates this from the shared secret we gave them earlier and the current time. Concurrently, the server generates a code in the same way. If both system clocks are in sync, the codes match and the user is validated.
It’s quite common for clocks to be slightly out (potentially up to a minute each way), so the server can compensate by generating additional codes that have been shifted in time; if one of these codes lines up with the user, we can still validate them.
This is just an overview — in practice, you’ll need to deal with more complexities (such as not allowing the same 2FA code to be submitted multiple times).
Python has the very handy PyOTP library, which takes care of pretty much everything for us.
import pyotp # Generate a new shared secret (or load one made previously) shared_secret = pyotp.random_base32() print("The TOTP seed is: %s" % shared_secret) # Make a TOTP object and get the current verification code totp = pyotp.TOTP(shared_secret) print("The TOTP code is: %s" % totp.now())
We can also generate a QR code to send to the user through the pyqrcode library.
import pyqrcode uri = totp.provisioning_url("firstname.lastname@example.org", "Cool App") qr = pyqrcode.create(uri) qr.png("output.png", scale=5)
I’m using this in a Browser context, so you’ll need to make changes if you’re using it inside Node.
// Create a shared secret var seed = window.otplib.authenticator.generateSecret(10); document.getElementById('totp_seed').value = seed; // Get the current token for the secret var otp = window.otplib.authenticator.generate(seed); document.getElementById('totp_token').value = otp; // Show the QR code in the 'totp_qr' <canvas> tag. var uri = window.otplib.authenticator.keyuri( 'email@example.com', 'sigsec', seed); QRCode.toCanvas(document.getElementById('totp_qr'), uri);
I’ve written a handy little Python TOTP tool that you can grab from my Github here. It should be a good starting point to see how to work with the two libraries I described above. It’s also fully functional, so feel free to put it through it’s paces!