How to implement TOTP in web application
MFA or Multi-factor authorization is a way which enhances an organization's security by asking their users to identify themselves not only by using a username and password but also by other means like entering a token that is sent to their mobile phone, or by entering a code that gets generated in authenticator apps like Google Authenticator and FreeOTP. Here we'll look at implementing such flow using PHP.
How does it work?
IETF has described the algorithm here which can be used to generate time-based OTP generation. Basically the algorithm generates a 6 digit code using a secret key and time; and it always generates the same code for specific time period (E.g. 30 secs). The secret key is shared with third-party apps like Google authenticator using a QR code and now that app is also able to generate the same 6 digit code that is valid for 30 secs. Again when the the third-party app generates a new code, it will be same as the one that your application generated provided the secret key is same and time is in sync. The secret key should be long enough so that its not easily guessable.
We now need a mechanism to generate a QR code using a secret key so that it can be shared with the third-party authenticator app and a way to verify the code given by those app. We'll be using Spomky-Labs/otphp for this purpose. This library requires at least PHP 8.1.
The purpose of this article is to provide you an information on how things work and quickly create a POC (proof of concept) for better understanding.
Step 1: Install
composer require spomky-labs/otphp
You might have to run composer dump-autoload
Step 2: Create a secret key
This can be a custom one or randomly generated. Here we use the library to generate a random secret key.
<?php
namespace OTPHP;
require_once __DIR__ . '/vendor/autoload.php';
$otpObj = TOTP::create();
$secretKey = $otpObj->getSecret();
echo "The OTP secret is: $secretKey";
//Output Eg. 2LYHXCEJRAQ7KTC2PF6R2UFCRQVGSNTHZV223CWVTJYNCDPZE4HFGHYFM2RQGKJ26XOBGMSN6XVARVRCWUVYK4CSWJ7XKAROYNQEHDI
You can run this code from terminal by running php secret.php if the name of the file is secret.php
If you are implementing it in your application, each user should have their own unique secret key preferably stored in a field in the users table.
Step 3: Generate the QR code
<?php
namespace OTPHP;
require_once __DIR__ . '/vendor/autoload.php';
$secret = '2LYHXCEJRAQ7KTC2PF6R2UFCRQVGSNTHZV223CWVTJYNCDPZE4HFGHYFM2RQGKJ26XOBGMSN6XVARVRCWUVYK4CSWJ7XKAROYNQEHDI';
$otpObj = TOTP::create($secret);
$otpObj->setLabel('Lamadly TOTP test');
$qrCodeUri = $otpObj->getQrCodeUri(
'https://api.qrserver.com/v1/create-qr-code/?data=' . $secret. '&size=300x300&ecc=M',
$secret
);
echo $qrCodeUri;
//echo "<img src='{$grCodeUri}'>";
Run the code in terminal and open the url in browser to get access to the QR code.
Step 4: Scan the QR from Google authenticator app
Step 5: Verify the code received from authenticator app
<?php
namespace OTPHP;
require_once __DIR__ . '/vendor/autoload.php';
$secret = '2LYHXCEJRAQ7KTC2PF6R2UFCRQVGSNTHZV223CWVTJYNCDPZE4HFGHYFM2RQGKJ26XOBGMSN6XVARVRCWUVYK4CSWJ7XKAROYNQEHDI';
$otpObj = TOTP::create($secret);
//Make sure to replace the code here with the one received from authenticator app
print_r($otpObj->verify('637722') ? 'valid token': 'invalid token');
//Alternatively you can also generate the token from your application to see if the tokens match
//echo "The current OTP is: {$otpObj->now()}\n";
Run this code in terminal to verify the OTP.
The above code should give you an understanding of how the flow works. To implement it in your application, you'll need to generate a secret code for each of your user and have an interface to share the QR code with your users.
Below is the flow diagram on how you can implement the time-based OTP in your application.

Latest Post
Information retrieval – Searching of text using Elasticsearch
Information retrieval is the process of obtaining relevant information resources from the collection of resources relevant to information need.
Learn more