Rest API Authentication in PHP Using Access Token Part 2

7 months ago admin PHP

In the second part of this tutorial, we will add user model & controller and we will add functions for registration login & logout.


Create UserModel

Inside models, we add a new file 'UserModel' Here we have functions for storing log-in logout, and generating access tokens for users.

                                                        
                                                                                                                        
<?php

namespace App\Models;
use App\Database\Database as DB;
use PDO;


class UserModel
{
    private $conn;

    public function __construct()
    {
        $database = new DB;
        $this->conn = $database->connect();
    }

    public function store($data)
    {
        $stmt = $this->conn->prepare('INSERT INTO users(name, email, password)
            VALUES (:name, :email, :password)');
        $stmt->bindParam(':name', $data['name']);
        $stmt->bindParam(':email', $data['email']);
        $stmt->bindParam(':password', $data['password']);
        $stmt->execute();
    }

    public function auth($data, $login) {
        $email = $data['email'];
        $stmt = $this->conn->prepare("SELECT * FROM users
            WHERE email = :email");
        $stmt->bindParam(':email', $email);
        $stmt->execute();
        $user = $stmt->fetch(PDO::FETCH_ASSOC);
        if($user && $login) {
            $user['api_key'] = $this->createApiKey($user['id']);
        }
        return $user;
    }

    public function signout($api_key, $user_id)
    {
        $this->removeApiKey($api_key, $user_id);
    }

    public function createApiKey($user_id)
    {
        $api_key = bin2hex(random_bytes(16));
        $stmt = $this->conn->prepare('INSERT INTO api_keys(user_id, api_key)
            VALUES (:user_id, :api_key)');
        $stmt->bindParam(':user_id', $user_id);
        $stmt->bindParam(':api_key', $api_key);
        $stmt->execute();
        return $api_key;
    }

    public function removeApiKey($api_key, $user_id)
    {
        $stmt = $this->conn->prepare("DELETE FROM api_keys
            WHERE user_id = :user_id AND api_key = :api_key");
        $stmt->bindParam(':user_id', $user_id);
        $stmt->bindParam(':api_key', $api_key);
        $stmt->execute();
    }

    public function checkIfApiKeyIsValid($api_key, $user_id)
    {
        $stmt = $this->conn->prepare("SELECT * FROM api_keys
            WHERE user_id = :user_id AND api_key = :api_key");
        $stmt->bindParam(':user_id', $user_id);
        $stmt->bindParam(':api_key', $api_key);
        $stmt->execute();
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        return $data;
    }
}

Create UserController

Inside controllers, we add a new file 'UserController' Here we call functions already added in the 'UserModel'.

                                                            
                                                                                                                                
<?php

namespace App\Controllers;
use App\Models\UserModel as User;

class UserController
{
    private $model;

    public function __construct()
    {
        $this->model = new User;
    }

    public function register($data)
    {
        $user = $this->model->auth($data, $login = false);
        if($user) {
            echo json_encode([
                'error' => true,
                'message' => 'You have already an account try to log in.'
            ]);
        }else {
            $options = [
                'const' => 12
            ];
            //hash password
            $password = password_hash($data['password'], PASSWORD_BCRYPT, $options);
            $data['password'] = $password;
            $this->model->store($data);
            echo json_encode([
                'message' => 'Account created successfully.'
            ]);
        }
    }

    public function login($data)
    {
        $user = $this->model->auth($data, $login = true);
        if(!$user) {
            echo json_encode([
                'error' => true,
                'message' => 'These credentials do not match any of our records.'
            ]);
        }else if(password_verify($data['password'], $user['password'])){
            unset($user['password']);
            echo json_encode([
                'user' => $user,
            ]);
        }else {
            echo json_encode([
                'error' => true,
                'message' => 'These credentials do not match any of our records.'
            ]);
        }
    }

    public function logout($data)
    {
        if(!$data['api_key'] || empty($data['api_key'])) {
            http_response_code(401);
            echo json_encode([
                'error' => true,
                'message' => 'unauthenticated'
            ]);
        }else if(!$this->model->checkIfApiKeyIsValid($data['api_key'], $data['user_id'])) {
            http_response_code(401);
            echo json_encode([
                'error' => true,
                'message' => 'unauthenticated'
            ]);
        }else {
            $this->model->signout($data['api_key'], $data['user_id']);
            echo json_encode([
                'message' => 'Logout successfully'
            ]);
        }
    }
}

Set index.php as default

Next, to set index.php as default once the user visits our app add the following code inside the file .htaccess.

                                                            
                                                                                                                                
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . index.php [L]

Add routes

Next, inside the file index.php, we add routes to register login and logout users.

                                                            
                                                                                                                                
<?php
//autoloading classes
require_once __DIR__.'/vendor/autoload.php';

//fix cross origin blocked
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
if ($method == "OPTIONS") {
    header('Access-Control-Allow-Origin: *');
    header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method,Access-Control-Request-Headers, Authorization");
    header("HTTP/1.1 200 OK");
    die();
}

//user actions
use App\Controllers\UserController as UserController;
$user = new UserController;

//break url to parts
$segments = explode("/", parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));

if($_SERVER['REQUEST_METHOD'] === 'POST' && $segments[1] === 'register' && empty($segments[2])) {
    $data = (array) json_decode(file_get_contents('php://input'), true);
    $user->register($data);
    exit;
}else if($_SERVER['REQUEST_METHOD'] === 'POST' && $segments[1] === 'login' && empty($segments[2])) {
    $data = (array) json_decode(file_get_contents('php://input'), true);
    $user->login($data);
    exit;
}else if($_SERVER['REQUEST_METHOD'] === 'POST' && $segments[1] === 'logout' && empty($segments[2])) {
    $data = (array) json_decode(file_get_contents('php://input'), true);
    $data['api_key'] = $_SERVER['HTTP_X_API_KEY'] ?? '';
    $user->logout($data);
    exit;
}else {
    http_response_code(404);
    echo json_encode([
        'error' => true,
        'message' => 'The page you are looking for does not exist.'
    ]);
}

Related Tuorials

How to Sort Associative Arrays in Descending Order According to the Key Value in PHP

in this lesson, we will see how to sort associative arrays in descending order according to the key...


How to Sort Associative Arrays in Ascending Order According to the Key Value in PHP

in this lesson, we will see how to sort associative arrays in ascending order according to the key v...


How to Sort Associative Arrays in Descending Order According to the Value in PHP

in this lesson, we will see how to sort associative arrays in descending order according to the valu...


How to Sort Associative Arrays in Ascending Order According to the Value in PHP

in this lesson, we will see how to sort associative arrays in ascending order according to the value...


How Do you Sort an Array in Descending Order in PHP

In this lesson, we will see how to sort descending an array in PHP, we will use the rsort() function...


How to Sort Ascending an Array in PHP

In this lesson, we will see how to sort ascending an array in PHP, we will use the sort() function t...


How to Remove a Key and its Value from an Associative Array in PHP

In this lesson, we will see how to remove a key and its value from an associative array in PHP,&nbsp...


How to Modify a Value in an Associative Array in PHP

In this lesson, we will see how to modify a value in an associative array in PHP, an Associative arr...


How to Add an Item to an Associative Array in PHP

In this lesson, we will see how to add an item to an associative array in PHP, an Associative array...


How to Add an Element to an Array in PHP

In this lesson, we will see how to add an element to an array in PHP, PHP has a built-in function th...