As a site owner, website security is one of the things that you must master and understand so that website users can safely use your site services. There are many methods to implement a security system on your site, one of which is implementing a Two Factor Authentication (2FA) system, this system can be implemented in the login system section which adds an additional layer of security to your site. In this article, we will provide a basic tutorial on how to implement a Two Factor Authentication (2FA) system using PHP, we will discuss how to generate a One Time Password number, generate a QR Code image and how to verify it.
Before getting into the topic, you need to know some requirements that must be met on your server to run this system, including the PHP version preferably using the latest version or above PHP 7.4, your server system has composer installed, and make sure the GD library is enabled, this library is used to generate QR Code image later.
1. Preparation
To understand how the files and folders are structured in implementing this case example, you can see the overview below:
2FA/
├── vendor/
├── composer.json
├── composer.lock
├── index.php
└── verify.php
To start this project, create the 2FA folder first then open your favorite code editor, open the terminal and run several libraries needed to run this 2FA system including:
composer require pragmarx/google2fa
composer require bacon/bacon-qr-code
We need to install the pragmarx/google2fa library to run Google Authenticator to generate a One Time Password code and verify it, then we also need a library to generate a QR Code using the library from bacon/bacon-qr-code.
Maybe for those who don't understand what the function of the QR Code is and why it is needed, the QR Code image itself will be used to integrate the 2FA system with a smartphone that has an authenticator application installed such as Google Authenticator, Authy or the like by scanning the QR Code image. The QR Code will store the information needed by the user to authenticate because this system will generate 1x number in 1x process. When the site asks for verification, the role of the authenticator application is needed.
Okay we continue, after the library installation process is complete, create 2 new files with the names index.php and verify.php, index.php is used as the main page to display and verify the code and the verify.php file is used to verify the code entered by the user:
2. Implementing Google Authenticator into the system
Next we will set up Google Authenticator using the pragmaRX library, this library will make it easier for you to implement this 2FA system, you don't need to create cURL implementation codes and others to integrate with Google Authenticator, here's how to implement it:
<?php
// Implement Google Authenticator with PHP (Two Factor Auth) - Genelify.com
require 'vendor/autoload.php';
use PragmaRX\Google2FA\Google2FA;
use BaconQrCode\Renderer\GDLibRenderer;
use BaconQrCode\Writer;
// Start Session
if(!session_id())
{
session_start();
}
// Initialize
$googleOTP = new Google2FA();
// Generate a secret key
$user = [
'google2fa_secret' => $googleOTP->generateSecretKey(),
'email' => '[email protected]'
];
// Store user data in the session
$_SESSION['user'] = $user;
// Provide name of app
$app_name = 'OTP authenticator implementation';
// Generate a custom URL from user data
$qrCodeUrl = $googleOTP->getQRCodeUrl($app_name, $user['email'], $user['google2fa_secret']);
The syntax above is part of index.php, which will generate a unique secret key for new users, this secret key must be stored in the Authenticator application, therefore we need a QR Code to store this information besides being safe and easy to implement.
3. Create a QR Barcode Image
Next we will create a QR barcode image using bacon/bacon-qr-code, the resulting image will later be used by the user to add an account to the authenticator application, here is the code to use this library using GD:
<?php
// Generate QR Code image with GD
$imageSize = 250;
$writer = new Writer(
new GDLibRenderer($imageSize)
);
// Create a string with the image base64 data
$encoded_qr_data = base64_encode($writer->writeString($qrCodeUrl));
The code above will create a URL that has been converted into an image that is already a QR Code with base64 format to be displayed in the frontend. Here is the complete syntax with HTML:
<?php
// Implement Google Authenticator with PHP (Two Factor Auth) - Genelify.com
require 'vendor/autoload.php';
use PragmaRX\Google2FA\Google2FA;
use BaconQrCode\Renderer\GDLibRenderer;
use BaconQrCode\Writer;
// Start Session
if(!session_id())
{
session_start();
}
// Initialize
$googleOTP = new Google2FA();
// Generate a secret key
$user = [
'google2fa_secret' => $googleOTP->generateSecretKey(),
'email' => '[email protected]'
];
// Store user data in the session
$_SESSION['user'] = $user;
// Provide name of app
$app_name = 'OTP authenticator implementation';
// Generate a custom URL from user data
$qrCodeUrl = $googleOTP->getQRCodeUrl($app_name, $user['email'], $user['google2fa_secret']);
// Generate QR Code image with GD
$imageSize = 250;
$writer = new Writer(
new GDLibRenderer($imageSize)
);
// Create a string with the image base64 data
$encoded_qr_data = base64_encode($writer->writeString($qrCodeUrl));
// Get current OTP (for debugging)
$current_otp = $googleOTP->getCurrentOtp($user['google2fa_secret']); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Google Authenticator with PHP - Genelify</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h1>Basic Implements Google Authenticator with PHP - Genelify</h1>
<div id="qrcode" style="margin-top: 20px;">
<p>Current generated OTP: <?php echo $current_otp; ?></p>
<img src="data:image/png;base64,<?php echo $encoded_qr_data; ?>"/>
</div>
<h2>Verify OTP</h2>
<form id="verify-form">
<input type="text" id="otp" placeholder="Input OTP code">
<button type="submit">Verify</button>
</form>
<script>
$(function()
{
// Verify OTP
$('#verify-form').on('submit', function(e) {
e.preventDefault();
var otp = $('#otp').val();
if(!otp) {
alert('Please input your OTP code!');
return false;
}
$.ajax({
url: 'verify.php',
method: 'POST',
data: { otp: otp },
dataType: 'json',
success: function(data) {
if(data.result) {
alert('OTP is successfully verified! with provided key: ' + data.provided_otp);
} else {
alert('OTP code is wrong! Please input valid OTP code!');
}
}
});
});
});
</script>
</body>
</html>
4. Verifying the OTP code
After the user adds their account to the authenticator application by scanning the image, the user will receive an OTP code that will change every 30 seconds from the Authenticator application, to verify it into the system, you need to add a new file, namely verify.php. Here is the syntax code:
<?php
// Implement Google Authenticator with PHP (Two Factor Auth) - Genelify.com
require 'vendor/autoload.php';
use PragmaRX\Google2FA\Google2FA;
// Start Session
if(!session_id())
{
session_start();
}
// Validate incoming request
if(empty($_POST['otp']) || empty($_SESSION['user']['google2fa_secret'])) {
die(json_encode(['result' => false]));
}
// Initialize
$googleOTP = new Google2FA();
// Retrieve One Time Password from payload
$otp = $_POST['otp'];
// Verify provided OTP
$isValid = $googleOTP->verifyKey($_SESSION['user']['google2fa_secret'], $otp);
// Generate and print JSON response
die(json_encode([
'provided_otp' => $otp,
'result' => $isValid
]));
This file is only specifically used to verify the code against the secret key that has been stored, if the verification process is successful the $isValid variable will return a boolean of true, if false it will return a boolean of false, and the implementation of Two Factor Authentication has been successful. As this is a basic implementation example, you will need to develop it further to apply to your system.
Conclusion
Implementing a Two Factor Authentication system on your system is actually not too difficult, because it has been made easier by the existence of libraries that make it easier to implement, by implementing this system your users will feel much safer when using your service. 2FA will add an extra layer of security to prevent things that are not wanted, especially when logging in on your site, because this system is mostly used in the login process or anything related to user data.