Two Factor Authentication (2FA) with Google Authenticator & PHP – Tutorial

Note: This tutorial is an improvement over the article written by Rich Barrett on way back in Nov 2017 (see this link). However, there are some missing parts in that article that are necessary to complete the circle. This write-up tried to address those gaps.


Google Authenticator is a token generator, that generates random and unique tokens for a validity of 30 seconds. Many web applications these days implement two-factor authentication in some form or the other. One of the popular methods is using an authenticator token, such as Google Authenticator.

According to Wikipedia – Google Authenticator is a software token that implements two-step verification services using the Time-based One-time Password Algorithm (TOTP) and HMAC-based One-time Password algorithm (HOTP), for authenticating users of mobile applications by Google.

Users generally authenticate their mobile phone, having this Google Authenticator app, by scanning a barcode generated in a web application. There after, the app constantly generates a new code for every 30 seconds. Users must use this code within the time to complete the login activity in the 2FA enabled web application. You can learn more about 2FA from’s definition.

PHP-based web applications can use this feature to authenticate users when they sign in. Let us see how we can get this implemented.

Database Schema

You may have to create a database table before starting the implementation. For  example, let us assume that you have a table with this structure.

Column Datatype
user_id INTEGER
user_name VARCHAR(50)
password VARCHAR(255)
email_id VARCHAR(255)
is_2fa_enabled TINYINT(1)

For demonstration, assume that this table this record.

user_id user_name password email_id is_2fa_enabled
1 krishna krishna [email protected] 1


Composer Package

Note: To add this package, your project should have composer setup initialized. See this link for necessary instructions.

Install a composer package sonata-project/google-authenticator. This package has the functionality to communicate with Google in getting the QR code and validating the number.  Install it with this command.

composer install sonata-project/google-authenticator

Generating QR code

Your users  need to add your application to their Google Authenticator app. They can do this by scanning a QR code generated on your website. Typically, this QR code has to be displayed in your application’s settings page, so that users will find it easily.

QR code will be generated by Google. So you have to show a simple image tag with a generated URL. The google-authenticator package has a method that will give your this URL.  But before calling the method, you need two things.

  1. Account name – the user identifier that you want to validate. In our example above, I will pickup user’s email_id, instead of the traditional user_name, to be more user friendly and unique. This will be displayed inside Google Authenticator app and can not be changed later. So, be selective.
  2. Secret key – random alphanumeric string. An easy way is to concatenate user_name to a salt value, such as XVQ2UIGO75XRUKJO.  Maintain this salt in your application’s configuration file, because you will need it again while validating the tokens.
  3. Issuer name – your application’s name. This will also be displayed inside the app, so be selective.

You have to maintain these values in your application’s configuration file as these will be required to generate QR code as well to validate the tokens.

require __DIR__ . '/vendor/autoload.php';

// get the user details from database
$userDetails = ....

// initialize your configuration
$config = .... 

// prepare data for request
$accountName = urlencode($userDetails['email_id']);
$secretKey   = $userDetails['user_name'].$config['salt']; 
$issuerName  = urlencode('My Fantastic Application');

// get the url
$qrCodeUrl = \Sonata\GoogleAuthenticator\GoogleQrUrl::generate($accountName, $secretKey, $issuerName);

URL in the QR code will be something like


Now show this to your user in HTML.

<img src="<?php echo $qrCodeUrl ?>" alt="QR Code" />

Adding in the Authenticator app

You or your users can now add your application in their device.

  1. Download and install Google Authenticator mobile app from Google Play Store of Apple App Store.
  2. Open the app and touch the + icon.
  3. Touch the “Scan Barcode” option. Camera opens up.
  4. Point the camera to the displayed QR code generated above.

If the scan is successful, an entry will be added in the app and token generation will start automatically.  If not, check whether you are sending the parameters properly or not. These are some common “Invalid barcode” errors.

Error: The barcode XXX is not a valid authentication token barcode
Reason: The QR code generated is not valid. Check the parameters sent.

Error: The barcode ‘otpauth://totp/xxx’ is not a valid authentication token barcode.
Reason: The parameters are not properly encoded. Check if all the special characters are converted properly or not.

Validating the tokens

Here comes the fun part !! When the user enters the token, you have to send it to Google to validate. So your code would be something like this. Make sure that you validate the inputs.

require __DIR__ . '/vendor/autoload.php'; 

// validate the login session 
// .... 

// get the user details from database 
$userDetails = ....

// initialize your configuration 
$config = .... 

// get the code and secret from form
$code  = $_POST['token_code']; 
$secretKey = $userDetails['user_name'].$config['salt']; 

// call Google
$isValidToken = $auth->checkCode($secretKey, $code);

$isValidToken will be a boolean value – true or false. If this is true, the user is in. If it is false, ask the user to re-enter the token.

Validity of the token is officially 30 seconds, but you can check it before 60 seconds. So you have another 30 seconds grace time after the token expires. (May be for those slow internet connection people??)

What’s next?

That’s it. Head on to the Google Authenticator Github and start the action.

Posted in php
error: Uh oh ...