How to Build Login and Registration RESTful API in PHP
In this step-by-step tutorial guide, you will learn how to create a simple login and registration API using PHP, MySQL and the “firebase/php-jwt” library for JWT handling.
1. Create MySQL Database and Table:
Create a MySQL database to store user information. You can use phpMyAdmin or the MySQL command line.
- Database Name:
php_login_api
- Database Table Name:
users
First, create a database called php_login_api
, then into the database create a table called users.
After creating the database, use the following SQL to create the users
table.
If you are using phpMyAdmin:
- Go to the SQL tab after selecting the
php_login_api
. - Paste the follwing sql code into the textarea and click on the
Go
button to excute this code. - After executing the code, you will see that the table is created and ready to use.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`email` varchar(50) NOT NULL,
`password` varchar(65) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
2. Setup the Project Folder:
Go in the root directory of your localhost which is htdocs
or www
, and then create a folder called login-api
(you can give any name), this is our project folder.
htdocs/
└── login-api/
3. Install the firebase/php-jwt Library:
For user authentication we will use JWT in this login-api project and therefore we need to install this library to handle JSON Web Tokens.
You can install this library via composer:
composer require firebase/php-jwt
For more you can see this tutorial: How to implement JWT in PHP
4. PHP Code for Login & Registration API:
After installing the JWT, we need to create 6 PHP files to build this PHP Authentication API. Here is the login-api
folder structure:
login-api/
├── vendor
├── composer.json
├── database.php
├── home.php
├── jwtHandler.php
├── login.php
├── register.php
└── sendJson.php
"database.php": For Database Connection
<?php
# database.php
$hostname = 'localhost';
$username = 'root';
$password = '';
$database = 'php_login_api';
$connection = mysqli_connect($hostname, $username, $password, $database);
if (mysqli_connect_errno()) {
echo "Connection Failed - " . mysqli_connect_error();
exit;
}
"sendJson.php": Send Response in JSON format
The sendJson.php
will be used to send response to the client in JSON format.
<?php
# sendJson.php
function sendJson(int $status, string $message, array $extra = []): void
{
$response = ['status' => $status];
if ($message) $response['message'] = $message;
http_response_code($status);
echo json_encode(array_merge($response, $extra));
exit;
}
"jwtHandler.php": Encode and Decode JWT Tokens
This file contains two functions:
encodeToken()
: For encoding or generating a new token.decodeToken()
: For verifying and decoding the token.
<?php
# jwtHandler.php
require_once __DIR__ . "/vendor/autoload.php";
require_once __DIR__ . "/sendJson.php";
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
$tokenSecret = 'my_strong_token_secret';
function encodeToken($data)
{
global $tokenSecret;
$token = array(
'iss' => 'http://localhost/php/login-api/',
'iat' => time(),
'exp' => time() + 3600, // 1hr
'data' => $data
);
return JWT::encode($token, $tokenSecret, 'HS256');
}
function decodeToken($token)
{
global $tokenSecret;
try {
$decode = JWT::decode($token, new Key($tokenSecret, 'HS256'));
return $decode->data;
} catch (ExpiredException | SignatureInvalidException $e) {
sendJson(401, $e->getMessage());
} catch (UnexpectedValueException | Exception $e) {
sendJson(400, $e->getMessage());
}
}
"register.php": For User Registration
The register.php contains the code for registering new users through the API.
<?php
# register.php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Content-Type: application/json; charset=UTF-8');
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');
exit;
}
require_once __DIR__ . '/database.php';
require_once __DIR__ . '/sendJson.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') :
$data = json_decode(file_get_contents('php://input'));
if (
!isset($data->name) ||
!isset($data->email) ||
!isset($data->password) ||
empty(trim($data->name)) ||
empty(trim($data->email)) ||
empty(trim($data->password))
) :
sendJson(
422,
'Please fill all the required fields & None of the fields should be empty.',
['required_fields' => ['name', 'email', 'password']]
);
endif;
$name = mysqli_real_escape_string($connection, htmlspecialchars(trim($data->name)));
$email = mysqli_real_escape_string($connection, trim($data->email));
$password = trim($data->password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) :
sendJson(422, 'Invalid Email Address!');
elseif (strlen($password) < 8) :
sendJson(422, 'Your password must be at least 8 characters long!');
elseif (strlen($name) < 3) :
sendJson(422, 'Your name must be at least 3 characters long!');
endif;
$hash_password = password_hash($password, PASSWORD_DEFAULT);
$sql = "SELECT `email` FROM `users` WHERE `email`='$email'";
$query = mysqli_query($connection, $sql);
$row_num = mysqli_num_rows($query);
if ($row_num > 0) sendJson(422, 'This E-mail already in use!');
$sql = "INSERT INTO `users`(`name`,`email`,`password`) VALUES('$name','$email','$hash_password')";
$query = mysqli_query($connection, $sql);
if ($query) sendJson(201, 'You have successfully registered.');
sendJson(500, 'Something going wrong.');
endif;
sendJson(405, 'Invalid Request Method. HTTP method should be POST');
Registering a New User (Testing):
POST - http://localhost/login-api/register.php
Payload (JSON)
{
"name":"username",
"email":"[email protected]",
"password":"user password"
}
"login.php": For login a user
<?php
# login.php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');
exit;
}
require_once __DIR__ . '/database.php';
require_once __DIR__ . '/jwtHandler.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') :
$data = json_decode(file_get_contents('php://input'));
if (
!isset($data->email) ||
!isset($data->password) ||
empty(trim($data->email)) ||
empty(trim($data->password))
) :
sendJson(
422,
'Please fill all the required fields & None of the fields should be empty.',
['required_fields' => ['email', 'password']]
);
endif;
$email = mysqli_real_escape_string($connection, trim($data->email));
$password = trim($data->password);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) :
sendJson(422, 'Invalid Email Address!');
elseif (strlen($password) < 8) :
sendJson(422, 'Your password must be at least 8 characters long!');
endif;
$sql = "SELECT * FROM `users` WHERE `email`='$email'";
$query = mysqli_query($connection, $sql);
$row = mysqli_fetch_array($query, MYSQLI_ASSOC);
if ($row === null) sendJson(404, 'User not found! (Email is not registered)');
if (!password_verify($password, $row['password'])) sendJson(401, 'Incorrect Password!');
sendJson(200, '', [
'token' => encodeToken($row['id'])
]);
endif;
sendJson(405, 'Invalid Request Method. HTTP method should be POST');
Testing of user login:
POST - http://localhost/login-api/login.php
Payload (JSON)
{
"email":"[email protected]",
"password":"user password"
}
"home.php": Accessing the user information via authorization token
- Here we check the Authorization header for a JWT token.
- If the token is present, we decode and verify it.
- If the user is authenticated, can see his/her Information. Otherwise, a
401
Unauthorized response is sent.
<?php
# home.php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET');
header("Content-Type: application/json; charset=UTF-8");
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Headers: Content-Type, Authorization');
exit;
}
require_once __DIR__ . '/database.php';
require_once __DIR__ . '/jwtHandler.php';
if ($_SERVER['REQUEST_METHOD'] == 'GET') :
$headers = getallheaders();
if (array_key_exists('Authorization', $headers) && preg_match('/Bearer\s(\S+)/', $headers['Authorization'], $matches)) :
$data = decodeToken($matches[1]);
$userId = (int) $data;
if (!is_numeric($data)) sendJson(401, 'Invalid User!');
$sql = "SELECT `id`,`name`,`email` FROM `users` WHERE `id`='$userId'";
$query = mysqli_query($connection, $sql);
$row = mysqli_fetch_array($query, MYSQLI_ASSOC);
if ($row === null) sendJson(404, 'User not found!');
sendJson(200, '', $row);
endif;
sendJson(403, "Authorization Token is Missing!");
endif;
sendJson(405, 'Invalid Request Method. HTTP method should be GET');
Testing the home.php
(trying to retirve an user data by using the token):
GET - http://localhost/login-api/home.php
Payload (Header)
Authorization - Bearer Token
The Job is done. Congratulations you have created a login registration API using PHP and MySQL.
Note: This is a very simple project that gives you a basic idea of building a PHP login and registration API with JWT.
There are a lot of things that you can implement in this project like – refresh token and logout feature, proper error handling, store secret keys properly, etc.
If you want to implement these in this project, you can checkout this repository: chandan-tudu/php-auth-api.