Create Login and Registration RESTful API in PHP

How to Make Login and Registration RESTful API in PHP?

In this step-by-step guide, we’ll build a simple Login and Registration API using PHP, MySQL, and the “firebase/php-jwt” library for JWT handling.

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

1. Set Up Your Development Environment:

Ensure you have PHP, a web server (e.g., Apache or Nginx), MySQL, and Composer installed on your machine. You can also use XAMPP or WAMP for an all-in-one solution.

2. Create a MySQL Database:

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;

Learn: How to use the above SQL code to create the users table using phpMyAdmin?

3. Create the Application Folder or Directory:

  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.

4. Install the Required Library:

In this project we will use JWT for Authorization. Therefore use Composer to install the “firebase/php-jwt library in the login-api folder for JWT handling:

composer require firebase/php-jwt

5. Create API Files:

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

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

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

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());
    }
}

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-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_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

login.php: For login user through API

<?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_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

home.php: Where users can see their Info

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-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_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 on Linkedin.

Thank You… Keep Learning 🙏❤️❤️