How To Make 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.

Follow the steps to build this PHP login and registration API

This guide assumes that you have PHP and MySQL set up, as well as Composer for managing dependencies.

Step 1: Create MySQL Database and Table for this project:

Create a MySQL database to store user information. You can use phpMyAdmin or the MySQL command line for this purpose.

  • 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. Use the following SQL code to create the users table and its structure:

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;

Step 2: Create a Folder or Directory for this Project:

  1. Go inside your XAMPP htdocs folder or your local server’s www directory,
  2. and here create a new folder called login-api,
  3. login-api is our Project or App folder.

Step 3: Install the firebase/php-jwt Library:

In this project we will use JWT for authorization. Therefore you need to install the “firebase/php-jwt” library via composer in the login-api folder for JWT handling:

composer require firebase/php-jwt

Step 4: Create PHP Files for this 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:

PHP login-api folder structure
PHP Login api project folder on VS code editor

1. “database.php”: For Database Connection

<?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;
}

2. “sendJson.php”: Send Response in JSON format

In this file you can see the sendJson.php that will be used to send response to the client in JSON format.

<?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;
}

3. “jwtHandler.php”: Encode and Decode JWT Tokens

This file contains two functions:

  • encodeToken(): For encoding a new token.
  • decodeToken(): For decoding the token.
<?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());
    }
}

4. “register.php”: For User Registration

The register.php contains the code for inserting new users through the API.

<?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');
POST - http://localhost/login-api/register.php
Payload (JSON)
{
    "name":"username",
    "email":"[email protected]",
    "password":"user password"
}
Testing of Register a new user through PHP API

5. “login.php”: For login user through API

<?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');
POST - http://localhost/login-api/login.php
Payload (JSON)
{
    "email":"[email protected]",
    "password":"user password"
}
Testing of Login user through PHP API

6. “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
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');
GET - http://localhost/login-api/home.php
Payload (Header)
Authorization - Bearer Token
Testing of Fetching the user data using access token through PHP API

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 features, proper error handling, store secret keys properly, etc. But, If you want me to make a project on this – let me know.

Thank You… Keep Learning 🙏❤️❤️

Leave a Reply

Your email address will not be published. Required fields are marked *

We use cookies to ensure that we give you the best experience on our website. Privacy Policy