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.

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:

  1. Go to the SQL tab after selecting the php_login_api.
  2. Paste the follwing sql code into the textarea and click on the Go button to excute this code.
  3. After executing the code, you will see that the table is created and ready to use.

Executing SQL code in phpmyadmin to create the users table for php_login_api database

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:

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

Registering a New User using php login api


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

Testing of Login user via php api


"home.php": Accessing the user information via authorization token

  1. Here we check the Authorization header for a JWT token.
  2. If the token is present, we decode and verify it.
  3. 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

Testing of retirving a user data by using the JWT 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.