Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

3 Steps to Create One Time Password (OTP) in PHP

INTRODUCTION
EXTRA SECURITY

Welcome to a tutorial on how to create a one time password (OTP) in PHP and MySQL. Need some extra security for your system? OTP is one of the ways to do so, and it can be used for literally anything – Resetting a user account, confirming an email address, payments, securing transactions, and so much more. So just how do we create a one-time password in PHP? This guide will walk you through the exact steps – Read on to find out.

I have included a zip file with all the source code at the end of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

CONFESSION
AN HONEST DISCLOSURE

Quick, hide your wallets! I am an affiliate partner of Google, eBay, Adobe, Bluehost, Clickbank, and more. There are affiliate links and advertisements throughout this website. Whenever you buy things from the evil links that I recommend, I will make a commission. Nah. These are just things to keep the blog going, and allows me to give more good stuff to you guys - for free. So thank you if you decide to pick up my recommendations!


 

NAVIGATION
TABLE OF CONTENTS

Section A
The Database

Section B
Library Files

Section C
Implementation Steps

Extra
Source Code Download

Closing
What’s Next?

SECTION A
THE DATABASE

First, we will need to establish a simple database table to store the generated OTP, timestamp, and stuff. 

OTP TABLE

sql/otp.sql
CREATE TABLE `otp` (
  `id` int(11) NOT NULL,
  `otp_pass` varchar(12) NOT NULL,
  `otp_timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `otp_tries` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `otp`
  ADD PRIMARY KEY (`id`);
FieldDescription
idThe primary key, unique identifier. This can be the user ID, transaction ID, order ID – Whatever you want to track.
otp_passThe one-time password.
otp_timestampTime at which the OTP is generated, used to calculate the expiry time.
otp_triesThe number of challenge attempts. Used to stop brute force attacks.

That is the gist of it, please feel free to make changes to fit your own project.

SECTION B
LIBRARY FILES

Next, we will need a PHP library to deal with the OTP magic and processes.

CONFIG FILE

lib/config.php

This is just a config file to hold all your settings – Remember to change the database and OTP settings to your own.

OTP LIBRARY

lib/lib-otp.php
pdo = new PDO(
        $str, DB_USER, DB_PASSWORD, [
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::ATTR_EMULATE_PREPARES => false
        ]
      );
      return true;
    }

    // ERROR - DO SOMETHING HERE
    // THROW ERROR MESSAGE OR SOMETHING
    catch (Exception $ex) {
      print_r($ex);
      die();
    }
  }

  function __destruct() {
  // __destruct() : close connection when done

    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }

  function exec($sql, $data=null) {
  // exec() : run insert, replace, update, delete query
  // PARAM $sql : SQL query
  //       $data : array of data

    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($data);
      $this->lastID = $this->pdo->lastInsertId();
    } catch (Exception $ex) {
      $this->error = $ex;
      return false;
    }
    $this->stmt = null;
    return true;
  }

  function fetch ($sql, $cond=null, $sort=null) {
  // fetch() : perform select query (single row expected)
  //           returns an array of column => value
  // PARAM $sql : SQL query
  //       $cond : array of conditions
  //       $sort : custom sort function

    $result = [];
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($cond);
      if (is_callable($sort)) {
        while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) {
          $result = $sort($row);
        }
      } else {
        while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) {
          $result = $row;
        }
      }
    } catch (Exception $ex) {
      $this->error = $ex;
      return false;
    }
    // Return result
    $this->stmt = null;
    return count($result)==0 ? false : $result ;
  }

  /* [OTP FUNCTIONS] */
  function randompass ($len) {
  // randompass() : create a random password
  // PARAM $len : random password length

    // Change this alphabets set as needed. For example, if you want numbers only
    // $alphabets = "0123456789";
    $alphabets = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    $count = strlen($alphabets) - 1;
    $pass = "";
    for ($i=0; $irandompass(OTP_LEN);

    // Database entry
    $sql = "REPLACE INTO `otp` (`id`, `otp_pass`, `otp_timestamp`, `otp_tries`) VALUES (?, ?, ?, ?)";
    $data = [$id, $pass, date("Y-m-d H:i:s"), 0];
    $ok = $this->exec($sql, $data);

    // Result
    return [
      "status" => $ok ? 1 : 0,
      "pass" => $ok ? $pass : ""
    ];
  }

  function challenge ($id, $pass) {
  // challenge() : challenge the OTP

    // Get the OTP entry
    $sql = "SELECT * FROM `otp` WHERE `id`=?";
    $data = [$id];
    $otp = $this->fetch($sql, $data);

    // OTP entry not found!?
    if ($otp === false) {
      $this->error = "OTP transaction not found.";
      return false;
    }

    // Too many tries
    if ($otp['otp_tries'] >= OTP_TRIES) {
      $this->error = "Too many tries for OTP.";
      return false;
    }

    // Expired
    $validTill = strtotime($otp['otp_timestamp']) + (OTP_VALID * 60);
    if (strtotime("now") > $validTill) {
      $this->error = "OTP has expired.";
      return false;
    }

    // Incorrect password
    if ($pass != $otp['otp_pass']) {
      // Add a strike to number of tries
      $strikes = $otp['otp_tries'] + 1;
      $sql = "UPDATE `otp` SET `otp_tries`=? WHERE `id`=?";
      $data = [$strikes, $id];
      $this->exec($sql, $data);

      // Security lock down - Too many tries
      if ($strikes >= OTP_TRIES) {
        $this->lockdown();
      }

      // Return result
      $this->error = "Incorrect OTP.";
      return false;
    }

    // OK - CORRECT OTP
    /* You can delete the OTP at this point if you want
     * $sql = "DELETE FROM `otp` WHERE `id`=?";
     * $data = [$id];
     * $this->exec($sql, $data);
     */
    return true;
  }

  function lockdown () {
  // lockdown() : failed challenge multiple times
    // @TODO - SECURITY LOCKDOWN
    // Suspend the user account?
    // Maybe temporary lock for a few hours to prevent spam?
    // Send warning email + SMS?
    // All up to your own system.
  }
}
?>

THE EXPLANATION

Yikes! This library looks complicated at first, but there are actually 2 parts to it –

  • Support functions that deal with the database.
  • Actual functions that deal with the OTP.

So if you are using your own PHP framework, please feel free to remove the database support functions, and update the OTP to use your framework.

Support Functions
FunctionDescription
__constructThe constructor. Automatically connects to the database when the OTP object is created.
__destructThe destructor. Automatically disconnects from the database when the OTP object is destroyed.
execRuns a insert, replace, update, or delete SQL query.
fetchPerform a select query.
OTP Functions
FunctionDescription
randompassGenerates a random password for the OTP.
initInitiates and creates a new OTP.
challengeChallenge the OTP.
lockdownSecurity lockdown. An empty function for you to fill in – This will run after the user has failed the OTP challenge too many times.

SECTION C
IMPLEMENTATION STEPS

With the foundations now established, the last step is to just use the OTP library into the project. As everyone has a different use for OTP, we will only walk through a very generic “how to implement” in this section.

1) GENERATE THE OTP

1-initialize.php
init(999);
 
// (3) SEND THE ONE-TIME PASSWORD TO THE USER
// (3A) OK - SEND OTP TO USER
if ($result['status'] == 1) {
  // Send message via email, SMS, messaging, or whatever communication gateway you use
  echo "Please visit https://your-site.com/page/ to verify. This password is valid for " . OTP_VALID . " minutes - " . $result['pass'];
}
// ERROR
else {
  echo "ERROR - ". $libOTP->error;
}
?>

The very first step of the process is to generate an OTP using the init() function – Just pass in the unique ID that you want to track, and remember to send the OTP and verification page to the user.

2) LANDING PAGE – OTP CHALLENGE

2-challenge.php


  
    
      OTP Challenge Demo Page
    
OTP Password
ID (This will be hidden or kept in the session)

This is an example landing page for the user to enter the OTP – Which is just a simple HTML form.

3) OTP VERIFICATION

3-verify.php
challenge($_POST['id'], $_POST['pass']);
} else {
  $libOTP->error = "Invalid OTP password and ID";
}

// (3) RESULTS
echo json_encode([
  "status" => $result ? 1 : 0,
  "message" => $result ? "OK" : $libOTP->error
]);
?>

Finally, we only have to verify the password that the user has provided.

EXTRA
DOWNLOAD

Finally, here is the download link as promised.

QUICK START

Skipped the entire tutorial? Here is a quick introduction to how the folders are being organized in the zip file.

  • ROOT The project root folder.
    • lib Where we store all the config and library files.
    • sql Contains the SQL for the OTP table.

So just import the SQL, update the settings in lib/config.php, and start tracing from 1-initialize.php.

SOURCE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
 

CLOSING
WHAT’S NEXT?

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you in your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

The post 3 Steps to Create One Time Password (OTP) in PHP appeared first on Code Boxx.



This post first appeared on Xxxxxxxxx, please read the originial post: here

Share the post

3 Steps to Create One Time Password (OTP) in PHP

×

Subscribe to Xxxxxxxxx

Get updates delivered right to your inbox!

Thank you for your subscription

×