Authenticate and log in your users using one-time passwords (OTP) via email.
Install via composer as metarush/otp-auth
In addition to your usual username
and/or email
column, create the ff. columns in your users table.
otpHash
TEXT (255)otpToken
TEXT(12)otpExpire
INT (10)rememberHash
TEXT (255)rememberToken
TEXT (12)
Note: You can use other column names if you want, just set them in the config.
The ff. example is meant to demonstrate the library's functionality in a simple way. It is not required to use this implementation as it is.
Create a _init.php
file to be included on top of your script and put the ff.
Initialize builder
$builder = new MetaRush\OtpAuth\Builder;
Define SMTP servers
$smtpServers = [
0 => $builder->SmtpServer()
->setHost('host')
->setUser('user')
->setPass('pass')
->setPort(465)
->setEncr('TLS'),
1 => $builder->SmtpServer()
->setHost('host2')
->setUser('user')
->setPass('pass')
->setPort(465)
->setEncr('TLS'),
];
You can add as many as you like, the lib will failover to each automatically.
Initialize the library with minimum config
$auth = $builder->setDsn('mysql:host=localhost;dbname=foo')
->setServers($smtpServers)
->setAdminEmails(['admin@example.com'])
->setAppName('foo')
->setFromEmail('noreply@example.com')
->setUsernameColumn('email')
->setNotificationFromEmail('noreply@example.com')
->setTable('users')
->build();
Note: If you want to extend Auth
class and still use the builder, you can pass
your child class in the build()
parameter as string. E.g. ->build('MyAuth');
Auto-login if username is remembered via cookie
if (!$auth->authenticated()) {
$rememberedUsername = $auth->rememberedUsername();
if (null !== $rememberedUsername)
$auth->login($rememberedUsername);
}
Create a login.php
file and put the ff.
<?php
include '_init.php';
if ($_POST) {
$username = $_POST['email'];
// check if username exists
if (!$auth->userExist($username))
exit('User does not exist');
// remember username for next page (otp.php)
setcookie('username', $username);
// send OTP to user's email
$otp = $auth->generateToken(5);
$auth->sendOtp($otp, $username);
// redirect to OTP page
header('location: otp.php');
}
?>
<?php if ($auth->authenticated()): ?>
You are already logged-in
<?php else: ?>
<form method="post">
Email: <input type="text" name="email" />
</form>
<?php endif; ?>
Create a otp.php
file and put the ff.
<?php
include '_init.php';
if ($_POST) {
$otp = $_POST['otp'];
$username = $_COOKIE['username'];
// remember username in browser if user wants to
if (isset($_POST['remember']))
$auth->remember($username);
// check if OTP is valid
if (!$auth->validOtp($otp, $username))
exit('Invalid OTP');
// login username
$auth->login($username);
echo 'OTP is valid';
// redirect to your restricted page
}
?>
<?php if ($auth->authenticated()): ?>
You are already logged-in
<?php else: ?>
<form method="post">
OTP: <input type="text" name="otp" />
<br />
<br />
Remember? <input type="checkbox" name="remember" />
<br />
<br />
<input type="submit" />
</form>
<?php endif; ?>
Create a logout.php
file and put the ff.
<?php
include '_init.php';
// destroy user session
$auth->logout();
You can use the ff. methods in the builder object, before the ->build();
method
Array of admin emails that will get error notifications
Label of your app on error notifications
Body of the OTP email. If you set this, you must include the template var {OTP}
.
Default: {OTP}\r\n\r\nNote: This OTP is valid for 5 minutes
Pool of characters where the token will be derived from
Default: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Cookie name prefix used by metarush/otp-auth
Default: MROA_
Cookie path used by metarush/otp-auth
Default: /
DB password of your users table
DB username of your users table
PDO DSN used to connect to your users table
Table column where users' email is stored
Default: email
From Email of the OTP message
From Name of the OTP message
If you set an admin email via setAdminEmail()
, you must set a From Email for error notifications
OTP expiration in minutes. If you set this, make sure to also change the email message via setBody(string);
to reflect the OTP expiration the email.
Default: 5
Table column where OTP expire is stored
Default: otpExpire
Table column where OTP hash is stored
Default: otpHash
Table column where OTP token is stored
Default: otpToken
How long "remember me" cookie expires in seconds
Default: 2592000
(30 days)
Table column name for "remember me" hash
Default: rememberHash
Table column name for lookup token for "remember me" cookie
Default: rememberToken
Array of SmtpServer
objects. See above sample "Define SMTP servers"
Subject of the OTP email
Default: Here's your OTP
Table where usernames will be authenticated
Default: users
Table column name where username is stored
Default: username
Table column name where userId is stored
Default: id
You can use round-robin mode to distribute the load to all SMTP hosts when sending OTP email.
To enable round-robin mode, you must use a storage driver to track the last server used to send email.
Available drivers and their config:
$driver = 'files';
$driverConfig = [
'path' => '/var/www/example/emailFallbackCache/'
];
$driver = 'memcached';
$driverConfig = [
'host' => '127.0.0.1',
'port' => 11211,
'saslUser' => '',
'saslPassword' => ''
];
Note: Only single server/non-distriubuted memcached is supported at the moment.
$driver = 'redis';
$driverConfig = [
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'database' => 0
];
Note: Use memcached or redis if available as files is not recommended for heavy usage.
After selecting a driver, set the following in the builder object, before the ->build();
method:
->setRoundRobinMode(true)
->setRoundRobinDriver($driver)
->setRoundRobinDriverConfig($driverConfig)
Check if user is authenticated
$length
Length of token you want to generate.
Generate random token
Log in user as authenticated
$username
Username to login
$userData
Optional arbitrary user data defined by you, e.g., firstName, email
Log out user and remove "remember me" cookie
Remember username's login in browser
$username
Username to remember
$howLong
How long to remember user in seconds. Default is value is 30 days unless setRememberCookieExpire()
was used in config.
Get remembered username (via cookie) if any.
$cookie
If null, default cookie will be used.
sendOtp(string $otp, string $username, bool $useNextSmtpHost = false, int $testLastServerKey = null): void
Send OTP to user via email
$otp
The OTP to send to user. You can use generateToken()
service method to generate random OTP. Recommended OTP length is at least 8.
$username
Username to send OTP to
$useNextSmtpHost
Set to true
on your next usage of sendOtp()
if you want to use the next SMTP host available relative to the current user. This is useful if the last email is slow to arrive. E.g., Create a "try again" UI then use sendOtp($otp, $username, true)
to send a new OTP using the next SMTP host.
Returns arbitrary user data, if set via login() param
Check if user exist
$username
Username to check
Validate OTP
$otp
OTP to be validated
$username
Username associated with the OTP
Check if OTP is expired
$username
Username associated with the OTP
Returns the userId of $username
$username
Username to get userId
We recommended using the metarush/firewall library for login brute-force protection.