In this tutorial, you will learn how to create a simple Login and Registration RESTful API using PHP and MySQL Database.
Before going further, if you wish you can read my already made tutorial on how to create CRUD RESTful API. Maybe this tutorial is a bit useful for you here.
PHP Login and Registration RESTful API
1. MySQL Database Setup
First, we will set up the MySQL Database for this application.
- Database Name –
php_auth_api
- Table Name –
users
Go inside your MySQL Database and create a new Database called php_auth_api
.
After that, use the following SQL code to create the users
table and the structure of this table –
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2. Creating files & folders
First, Open your Xampp htdocs dir or your server www dir, and here create a new folder called php-auth-api
. This is our application folder.
After that, you need to install JWT inside this folder, as we will be using it for authorization. You can get help from here – How to implement JWT with PHP.
Now we need to create the folders and files as given in the following image of the php-auth-api
folder structure.


📁 classes Folder Setup
Inside the application folder, you need to create a new folder called classes, and inside the classes folder, we will create two files or classes –
Database.php
– For making the database connection.JwtHandler.php
– For handling the JWT actions like encoding and decoding token.
<?php
class Database{
// CHANGE THE DB INFO ACCORDING TO YOUR DATABASE
private $db_host = 'localhost';
private $db_name = 'php_auth_api';
private $db_username = 'root';
private $db_password = '';
public function dbConnection(){
try{
$conn = new PDO('mysql:host='.$this->db_host.';dbname='.$this->db_name,$this->db_username,$this->db_password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $conn;
}
catch(PDOException $e){
echo "Connection error ".$e->getMessage();
exit;
}
}
}
<?php
require './vendor/autoload.php';
use Firebase\JWT\JWT;
class JwtHandler
{
protected $jwt_secrect;
protected $token;
protected $issuedAt;
protected $expire;
protected $jwt;
public function __construct()
{
// set your default time-zone
date_default_timezone_set('Asia/Kolkata');
$this->issuedAt = time();
// Token Validity (3600 second = 1hr)
$this->expire = $this->issuedAt + 3600;
// Set your secret or signature
$this->jwt_secrect = "this_is_my_secrect";
}
public function jwtEncodeData($iss, $data)
{
$this->token = array(
//Adding the identifier to the token (who issue the token)
"iss" => $iss,
"aud" => $iss,
// Adding the current timestamp to the token, for identifying that when the token was issued.
"iat" => $this->issuedAt,
// Token expiration
"exp" => $this->expire,
// Payload
"data" => $data
);
$this->jwt = JWT::encode($this->token, $this->jwt_secrect, 'HS256');
return $this->jwt;
}
public function jwtDecodeData($jwt_token)
{
try {
$decode = JWT::decode($jwt_token, $this->jwt_secrect, array('HS256'));
return [
"data" => $decode->data
];
} catch (Exception $e) {
return [
"message" => $e->getMessage()
];
}
}
}
AuthMiddleware.php
This file is for checking whether the token is valid or not.
<?php
require __DIR__ . '/classes/JwtHandler.php';
class Auth extends JwtHandler
{
protected $db;
protected $headers;
protected $token;
public function __construct($db, $headers)
{
parent::__construct();
$this->db = $db;
$this->headers = $headers;
}
public function isValid()
{
if (array_key_exists('Authorization', $this->headers) && preg_match('/Bearer\s(\S+)/', $this->headers['Authorization'], $matches)) {
$data = $this->jwtDecodeData($matches[1]);
if (
isset($data['data']->user_id) &&
$user = $this->fetchUser($data['data']->user_id)
) :
return [
"success" => 1,
"user" => $user
];
else :
return [
"success" => 0,
"message" => $data['message'],
];
endif;
} else {
return [
"success" => 0,
"message" => "Token not found in request"
];
}
}
protected function fetchUser($user_id)
{
try {
$fetch_user_by_id = "SELECT `name`,`email` FROM `users` WHERE `id`=:id";
$query_stmt = $this->db->prepare($fetch_user_by_id);
$query_stmt->bindValue(':id', $user_id, PDO::PARAM_INT);
$query_stmt->execute();
if ($query_stmt->rowCount()) :
return $query_stmt->fetch(PDO::FETCH_ASSOC);
else :
return false;
endif;
} catch (PDOException $e) {
return null;
}
}
}
Rest of the PHP files
register.php
– For user registration.login.php
– For user login.getUser.php
– After login, this page is accessible with a valid token.
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__ . '/classes/Database.php';
$db_connection = new Database();
$conn = $db_connection->dbConnection();
function msg($success, $status, $message, $extra = [])
{
return array_merge([
'success' => $success,
'status' => $status,
'message' => $message
], $extra);
}
// DATA FORM REQUEST
$data = json_decode(file_get_contents("php://input"));
$returnData = [];
if ($_SERVER["REQUEST_METHOD"] != "POST") :
$returnData = msg(0, 404, 'Page Not Found!');
elseif (
!isset($data->name)
|| !isset($data->email)
|| !isset($data->password)
|| empty(trim($data->name))
|| empty(trim($data->email))
|| empty(trim($data->password))
) :
$fields = ['fields' => ['name', 'email', 'password']];
$returnData = msg(0, 422, 'Please Fill in all Required Fields!', $fields);
// IF THERE ARE NO EMPTY FIELDS THEN-
else :
$name = trim($data->name);
$email = trim($data->email);
$password = trim($data->password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) :
$returnData = msg(0, 422, 'Invalid Email Address!');
elseif (strlen($password) < 8) :
$returnData = msg(0, 422, 'Your password must be at least 8 characters long!');
elseif (strlen($name) < 3) :
$returnData = msg(0, 422, 'Your name must be at least 3 characters long!');
else :
try {
$check_email = "SELECT `email` FROM `users` WHERE `email`=:email";
$check_email_stmt = $conn->prepare($check_email);
$check_email_stmt->bindValue(':email', $email, PDO::PARAM_STR);
$check_email_stmt->execute();
if ($check_email_stmt->rowCount()) :
$returnData = msg(0, 422, 'This E-mail already in use!');
else :
$insert_query = "INSERT INTO `users`(`name`,`email`,`password`) VALUES(:name,:email,:password)";
$insert_stmt = $conn->prepare($insert_query);
// DATA BINDING
$insert_stmt->bindValue(':name', htmlspecialchars(strip_tags($name)), PDO::PARAM_STR);
$insert_stmt->bindValue(':email', $email, PDO::PARAM_STR);
$insert_stmt->bindValue(':password', password_hash($password, PASSWORD_DEFAULT), PDO::PARAM_STR);
$insert_stmt->execute();
$returnData = msg(1, 201, 'You have successfully registered.');
endif;
} catch (PDOException $e) {
$returnData = msg(0, 500, $e->getMessage());
}
endif;
endif;
echo json_encode($returnData);
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__.'/classes/Database.php';
require __DIR__.'/classes/JwtHandler.php';
function msg($success,$status,$message,$extra = []){
return array_merge([
'success' => $success,
'status' => $status,
'message' => $message
],$extra);
}
$db_connection = new Database();
$conn = $db_connection->dbConnection();
$data = json_decode(file_get_contents("php://input"));
$returnData = [];
// IF REQUEST METHOD IS NOT EQUAL TO POST
if($_SERVER["REQUEST_METHOD"] != "POST"):
$returnData = msg(0,404,'Page Not Found!');
// CHECKING EMPTY FIELDS
elseif(!isset($data->email)
|| !isset($data->password)
|| empty(trim($data->email))
|| empty(trim($data->password))
):
$fields = ['fields' => ['email','password']];
$returnData = msg(0,422,'Please Fill in all Required Fields!',$fields);
// IF THERE ARE NO EMPTY FIELDS THEN-
else:
$email = trim($data->email);
$password = trim($data->password);
// CHECKING THE EMAIL FORMAT (IF INVALID FORMAT)
if(!filter_var($email, FILTER_VALIDATE_EMAIL)):
$returnData = msg(0,422,'Invalid Email Address!');
// IF PASSWORD IS LESS THAN 8 THE SHOW THE ERROR
elseif(strlen($password) < 8):
$returnData = msg(0,422,'Your password must be at least 8 characters long!');
// THE USER IS ABLE TO PERFORM THE LOGIN ACTION
else:
try{
$fetch_user_by_email = "SELECT * FROM `users` WHERE `email`=:email";
$query_stmt = $conn->prepare($fetch_user_by_email);
$query_stmt->bindValue(':email', $email,PDO::PARAM_STR);
$query_stmt->execute();
// IF THE USER IS FOUNDED BY EMAIL
if($query_stmt->rowCount()):
$row = $query_stmt->fetch(PDO::FETCH_ASSOC);
$check_password = password_verify($password, $row['password']);
// VERIFYING THE PASSWORD (IS CORRECT OR NOT?)
// IF PASSWORD IS CORRECT THEN SEND THE LOGIN TOKEN
if($check_password):
$jwt = new JwtHandler();
$token = $jwt->jwtEncodeData(
'http://localhost/php_auth_api/',
array("user_id"=> $row['id'])
);
$returnData = [
'success' => 1,
'message' => 'You have successfully logged in.',
'token' => $token
];
// IF INVALID PASSWORD
else:
$returnData = msg(0,422,'Invalid Password!');
endif;
// IF THE USER IS NOT FOUNDED BY EMAIL THEN SHOW THE FOLLOWING ERROR
else:
$returnData = msg(0,422,'Invalid Email Address!');
endif;
}
catch(PDOException $e){
$returnData = msg(0,500,$e->getMessage());
}
endif;
endif;
echo json_encode($returnData);
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__.'/classes/Database.php';
require __DIR__.'/AuthMiddleware.php';
$allHeaders = getallheaders();
$db_connection = new Database();
$conn = $db_connection->dbConnection();
$auth = new Auth($conn, $allHeaders);
echo json_encode($auth->isValid());
3. Testing of the PHP login and registration API
3.1 register.php
POST - http://localhost/php-auth-api/register.php
Payload (JSON)
{
"name":"username",
"email":"[email protected]",
"password":"user password"
}


3.2 login.php
POST - http://localhost/php-auth-api/login.php
Payload (JSON)
{
"email":"useremail@mail.com",
"password":"user password"
}


3.3 getUser.php
GET - http://localhost/php-auth-api/getUser.php
Payload (Header)
Authorization - Bearer Token


How I can email verification system on this program? Please Help Me
This project will come soon.
I am looking for email verification on this too.. would be great!
Dear Sir/Madam,
I can’t get the user_info even I ensure everythings input correctly.
I add code
`echo json_encode($allHeaders);`
under
`$allHeaders = getallheaders();`
I can’t find the Authorization header from the echo, I did add the Authorization header, what did I miss from the postman?
I try to bypass the checking headers, and I still get Unauthorized return, I reviewed the Auth.php, it extends the JwtHandler class, it checks the $data[‘data’]->user_id but I review the _jwt_decode_data() but I can’t find how the user_id will be passed
$data = $this->_jwt_decode_data($this->token[1]);
if(isset($data[‘auth’]) && isset($data[‘data’]->user_id) && $data[‘auth’]):
$user = $this->fetchUser($data[‘data’]->user_id);
return $user;
Could you advise how I can make it work?
Best regards,
Kelvin.
I finally found the reason, hope it can help others having such problem.
Adding below in .htaccess file to
SetEnvIf Authorization “(.*)” HTTP_AUTHORIZATION=$1
How to test the API Connection, PLease help i am new here.
You can use the postman software.
Hi
i wonder how can i convert this API’s link from http to https ?
You have to install SSL on your hosting.
Hi
I deployed these files in my WordPress website and login/signup APIs are working fine, but user-info gives me Unauthorized error every time. (tested on postman with Bearer token). Let me know if any additional setup is required.
Thanks
I tested in my local server, it’s working fine. I think you are making some mistake that you are not conscious about. Please try to find it. OR you can send some images to [email protected]
This is by far the best tutorial available on the internet to learn integration of PHP/mysql with react. I am truly grateful for this help that has helped me advance my knowledge and skills. Thanks indeed.
Can you please share the code to reset the password for users who forgot password
Yes, but you’ll have to wait.