How to Implement Google Authenticator 2FA Login in PHP

Published on September 24, 2025 by @mritxperts

Passwords alone aren’t enough to keep your application secure. Attackers often crack or steal credentials, which is why Two-Factor Authentication (2FA) has become standard in modern applications.

In this tutorial, we’ll build a PHP login system with Google Authenticator that requires both a password and a one-time code from the user’s phone.


Prerequisites

  • PHP 7.4+ with MySQL/MariaDB
  • Composer installed
  • Basic understanding of PHP sessions and authentication

Step 1: Install Google Authenticator Library

Run this in your project folder:

composer require sonata-project/google-authenticator

Step 2: Database Setup

Create a table for storing users and their 2FA secret.

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(100) NOT NULL,
    password VARCHAR(255) NOT NULL,
    secret VARCHAR(255) DEFAULT NULL
);

Step 3: Registration with QR Code

When a user registers, generate a secret key and QR code.

<?php
// register.php
require 'vendor/autoload.php';
use Sonata\GoogleAuthenticator\GoogleAuthenticator;
use Sonata\GoogleAuthenticator\GoogleQrUrl;

$pdo = new PDO("mysql:host=localhost;dbname=yourdb", "root", "");

// Handle registration
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'];
    $password = password_hash($_POST['password'], PASSWORD_BCRYPT);

    $g = new GoogleAuthenticator();
    $secret = $g->generateSecret();

    $stmt = $pdo->prepare("INSERT INTO users (username, password, secret) VALUES (?, ?, ?)");
    $stmt->execute([$username, $password, $secret]);

    $qrCodeUrl = GoogleQrUrl::generate($username, $secret, 'MySecureApp');
}
?>
<!DOCTYPE html>
<html>
<head><title>Register</title></head>
<body>
<h2>Register</h2>
<form method="post">
    Username: <input type="text" name="username" required><br>
    Password: <input type="password" name="password" required><br>
    <button type="submit">Register</button>
</form>

<?php if (!empty($qrCodeUrl)): ?>
    <h3>Scan this QR Code in Google Authenticator</h3>
    <img src="<?= $qrCodeUrl ?>">
<?php endif; ?>
</body>
</html>

👉 After registration, users must scan the QR code in the Google Authenticator app.


Step 4: Login with Password + OTP

First, verify username/password. If correct, ask for OTP.

<?php
// login.php
require 'vendor/autoload.php';
session_start();

$pdo = new PDO("mysql:host=localhost;dbname=yourdb", "root", "");

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    $stmt = $pdo->prepare("SELECT * FROM users WHERE username=?");
    $stmt->execute([$username]);
    $user = $stmt->fetch();

    if ($user && password_verify($password, $user['password'])) {
        $_SESSION['pending_user'] = $user;
        header("Location: verify.php");
        exit;
    } else {
        echo "❌ Invalid username or password";
    }
}
?>
<!DOCTYPE html>
<html>
<head><title>Login</title></head>
<body>
<h2>Login</h2>
<form method="post">
    Username: <input type="text" name="username" required><br>
    Password: <input type="password" name="password" required><br>
    <button type="submit">Login</button>
</form>
</body>
</html>

Step 5: OTP Verification

<?php
// verify.php
require 'vendor/autoload.php';
use Sonata\GoogleAuthenticator\GoogleAuthenticator;
session_start();

if (!isset($_SESSION['pending_user'])) {
    header("Location: login.php");
    exit;
}

$user = $_SESSION['pending_user'];
$g = new GoogleAuthenticator();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $code = $_POST['otp_code'];
    if ($g->checkCode($user['secret'], $code)) {
        $_SESSION['authenticated'] = true;
        $_SESSION['username'] = $user['username'];
        unset($_SESSION['pending_user']);
        header("Location: dashboard.php");
        exit;
    } else {
        echo "❌ Invalid OTP, try again.";
    }
}
?>
<!DOCTYPE html>
<html>
<head><title>Verify OTP</title></head>
<body>
<h2>Enter 6-digit code from Google Authenticator</h2>
<form method="post">
    <input type="text" name="otp_code" required maxlength="6"><br>
    <button type="submit">Verify</button>
</form>
</body>
</html>

Step 6: Dashboard Page (Protected)

<?php
// dashboard.php
session_start();
if (!isset($_SESSION['authenticated'])) {
    header("Location: login.php");
    exit;
}
?>
<!DOCTYPE html>
<html>
<head><title>Dashboard</title></head>
<body>
<h2>Welcome, <?= htmlspecialchars($_SESSION['username']) ?> 🎉</h2>
<p>You are logged in with 2FA enabled!</p>
<a href="logout.php">Logout</a>
</body>
</html>

Step 7: Logout

<?php
// logout.php
session_start();
session_destroy();
header("Location: login.php");
exit;

Security Best Practices

  • Use HTTPS in production.
  • Store passwords with password_hash() and password_verify().
  • Protect against brute-force by limiting login attempts.
  • Provide backup codes or an option to disable 2FA via email verification in case the user loses their phone.

✅ Conclusion

We built a complete Google Authenticator 2FA login system in PHP:

  1. User registers → gets QR code.
  2. User logs in → enters username & password.
  3. User enters OTP from Google Authenticator.
  4. If correct, access is granted.

This simple setup greatly improves account security and can be integrated into any existing PHP application.