PHP REST API Authentication Using JWT

2022.07.15 20:44

졸리운_곰 조회 수:13

PHP REST API Authentication Using JWT

Introduction

Here in this tutorial, PHP REST API authentication using JWT, you will see how to use JWT (JSON Web Token) to authorize users and allow them to continue their works once they are logged in using their regular credentials (usernames and passwords). Users use their credentials to get the JWTs and continue their work until JWTs expire. In this example, I will not use any third party library to generate JWT.

You might have seen how to generate and validate JWT using PHP language without using any third party library. Here I will use the same concept to generate the JWT for individual user and allow him/her continue his/her work until JWT expires.

 

I will create REST APIs in PHP for individual functionality, such as, for login I will create a separate REST API, for registration I will craete a separate REST API.

Prerequisites

PHP 7.3.5 – 7.4.23, Apache 2.4 (Optional), MySQL 8.0.17 – 8.0.26, REST Client – Talend, Postman, Firefox, etc.

MySQL Table

Create a table user in MySQL server under roytuts database.

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(45) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

I insert one row with sample data into the database to test the application right away:

insert into user(`username`, `password`) value(‘roy’, ‘roy’);

Project Directory

It’s assumed that you have setup Apache (Optional, you can use built-in PHP development server), PHP and MySQL in Windows system.

Now I will create a project root directory called php-jwt-rest-authentication under the Apache server’s htdocs folder. I may not mention the project root directory in subsequent sections and I will assume that I am talking with respect to the project root directory.

Database Configuration

Create db.php file for various database operations, such as, inserting data into MySQL database, selecting data from MySQL database, etc. Please do not forget to change the database credentials as per your database.

<?php

/**
* Author : https://roytuts.com
*/
	
$dbConn = mysqli_connect('localhost', 'root', 'root', 'roytuts') or die('MySQL connect failed. ' . mysqli_connect_error());

function dbQuery($sql) {
	global $dbConn;
	$result = mysqli_query($dbConn, $sql) or die(mysqli_error($dbConn));
	return $result;
}

function dbFetchAssoc($result) {
	return mysqli_fetch_assoc($result);
}

function dbNumRows($result) {
    return mysqli_num_rows($result);
}

function closeConn() {
	global $dbConn;
	mysqli_close($dbConn);
}
	
//End of file

User Registration

In order to gain access to the system, user has to first get himself/herself registered by creating username and password. The real application will capture much more data about a user but for simplicity I am capturing little information.

I did not use any encryption technology and storing password as a plain text but ideally you should never do this for your real application.

The below REST API allows any origin to be accessible for http method POST only. JSON parameter will be used in the request body for creating new resource, i.e., for registering the new user.

I will create a PHP file called register.php with the following code:

<?php

/**
* Author : https://roytuts.com
*/

require_once 'db.php';

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
	// get posted data
	$data = json_decode(file_get_contents("php://input", true));
	
	$sql = "INSERT INTO user(username, password) VALUES('" . mysqli_real_escape_string($dbConn, $data->username) . "', '" . mysqli_real_escape_string($dbConn, $data->password) . "')";
	
	$result = dbQuery($sql);
	
	if($result) {
		echo json_encode(array('success' => 'You registered successfully'));
	} else {
		echo json_encode(array('error' => 'Something went wrong, please contact administrator'));
	}
}

//End of file

In PHP I have retrieved the JSON body parameter using the following code.

file_get_contents("php://input", true)

Finally I have decoded the JSON parameters to access as an object using the function json_decode().

Here is an example on how to register a new user. You can use any REST client to register or create a new user.

Http Method - POST
URL - http://localhost/php-jwt-rest-authentication/register.php
Request Body - {"username":"roy", "password":"roy"}
Header - Content-Type:application/json
Response - {"success":"You registered successfully"}

User Login

The registered user will be able to login to the application and will get the generated JWT. Then this generated JWT will be used to access designated REST APIs over http protocol.

The JWT is valid only for 60 seconds or 1 minute, please change to suit your requirements.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

Create a file login.php with the following source code:

<?php

/**
* Author : https://roytuts.com
*/

require_once 'db.php';
require_once 'jwt_utils.php';

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
	// get posted data
	$data = json_decode(file_get_contents("php://input", true));
	
	$sql = "SELECT * FROM user WHERE username = '" . mysqli_real_escape_string($dbConn, $data->username) . "' AND password = '" . mysqli_real_escape_string($dbConn, $data->password) . "' LIMIT 1";
	
	$result = dbQuery($sql);
	
	if(dbNumRows($result) < 1) {
		echo json_encode(array('error' => 'Invalid User'));
	} else {
		$row = dbFetchAssoc($result);
		
		$username = $row['username'];
		
		$headers = array('alg'=>'HS256','typ'=>'JWT');
		$payload = array('username'=>$username, 'exp'=>(time() + 60));

		$jwt = generate_jwt($headers, $payload);
		
		echo json_encode(array('token' => $jwt));
	}
}

//End of file

Here is an example on how to login and get the generated JWT:

Http Method - POST
URL - http://localhost/php-jwt-rest-authentication/login.php
Request Body - {"username":"roy", "password":"roy"}
Header - Content-Type:application/json
Response - {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJveSIsImV4cCI6MTU4MjYyMDY1OX0.EMTwnke-M5PXV3LEEUveZLcvvi7pQmGUbWMAj2KeR94"}

Access REST API

Now I will use the generated JWT to access the REST API that list all users from the MySQL database table to the user who is having valid JWT.

I accept HTTP method GET and allow access to anyone.

Create a file users.php with the following source code:

<?php

/**
* Author : https://roytuts.com
*/

require_once 'db.php';
require_once 'jwt_utils.php';

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");

$bearer_token = get_bearer_token();

#echo $bearer_token;

$is_jwt_valid = is_jwt_valid($bearer_token);

if($is_jwt_valid) {
	$sql = "SELECT * FROM user";
	$results = dbQuery($sql);

	$rows = array();

	while($row = dbFetchAssoc($results)) {
		$rows[] = $row;
	}

	echo json_encode($rows);
} else {
	echo json_encode(array('error' => 'Access denied'));
}

//End of file

Here is an example on how to access the REST API:

Http Method - GET
URL - http://localhost/php-jwt-rest-authentication/users.php
Request Body - {"username":"roy", "password":"roy"}
Header - Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJveSIsImV4cCI6MTU4MjYyMDY1OX0.EMTwnke-M5PXV3LEEUveZLcvvi7pQmGUbWMAj2KeR94
Response - [{"id":"1","username":"roy","password":"roy"},{"id":"2","username":"soumitra","password":"roy"}]

In the above response you see two users because I have registered two users but I had shown only one user during registration process.

JWT Generation and Validation

The below PHP script defines the required functions to generate, validate JWT and extract the Bearer token from Authorization header of http request.

<?php

function generate_jwt($headers, $payload, $secret = 'secret') {
	$headers_encoded = base64url_encode(json_encode($headers));
	
	$payload_encoded = base64url_encode(json_encode($payload));
	
	$signature = hash_hmac('SHA256', "$headers_encoded.$payload_encoded", $secret, true);
	$signature_encoded = base64url_encode($signature);
	
	$jwt = "$headers_encoded.$payload_encoded.$signature_encoded";
	
	return $jwt;
}

function is_jwt_valid($jwt, $secret = 'secret') {
	// split the jwt
	$tokenParts = explode('.', $jwt);
	$header = base64_decode($tokenParts[0]);
	$payload = base64_decode($tokenParts[1]);
	$signature_provided = $tokenParts[2];

	// check the expiration time - note this will cause an error if there is no 'exp' claim in the jwt
	$expiration = json_decode($payload)->exp;
	$is_token_expired = ($expiration - time()) < 0;

	// build a signature based on the header and payload using the secret
	$base64_url_header = base64url_encode($header);
	$base64_url_payload = base64url_encode($payload);
	$signature = hash_hmac('SHA256', $base64_url_header . "." . $base64_url_payload, $secret, true);
	$base64_url_signature = base64url_encode($signature);

	// verify it matches the signature provided in the jwt
	$is_signature_valid = ($base64_url_signature === $signature_provided);
	
	if ($is_token_expired || !$is_signature_valid) {
		return FALSE;
	} else {
		return TRUE;
	}
}

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function get_authorization_header(){
	$headers = null;
	
	if (isset($_SERVER['Authorization'])) {
		$headers = trim($_SERVER["Authorization"]);
	} else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
		$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
	} else if (function_exists('apache_request_headers')) {
		$requestHeaders = apache_request_headers();
		// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
		$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
		//print_r($requestHeaders);
		if (isset($requestHeaders['Authorization'])) {
			$headers = trim($requestHeaders['Authorization']);
		}
	}
	
	return $headers;
}

function get_bearer_token() {
    $headers = get_authorization_header();
	
    // HEADER: Get the access token from the header
    if (!empty($headers)) {
        if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
            return $matches[1];
        }
    }
    return null;
}

In the above code snippets the most important functions are get_authorization_header() and get_bearer_token(). These functions are used to get the required Bearer token from Authorization header.

Start Development Server

Now to start the development server, navigate to the root folder of your project from the command line tool and execute the command: php -S localhost:8000.

Your development server will start and listen to port 8000.

Testing JWT Authentication

 

Use the following details as highlighed in the screen-shot to generate the JWT using REST client tool:

image-67-1024x380.png

 

Use the above generated JWT token in the HTTP header under Authorization key with the values as Bearer <JWT>.

image-68-1024x409.png

 

Source Code

 

Download

 

[출처] https://roytuts.com/php-rest-api-authentication-using-jwt/

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
149 [MySQL+PHP] MySQL 접속후 데이터 가져오기 졸리운_곰 2024.04.18 0
148 [php] [xampp] xampp php 버전 폴더 (디렉토리) 별 설정 : Running multiple PHP versions on XAMPP file 졸리운_곰 2024.03.21 3
147 [php] [PHP] Laravel - PayPal 결제 모듈 연동하기 (2) - 백엔드 처리 file 졸리운_곰 2024.03.17 1
146 [php] [PHP] Laravel - PayPal 결제 모듈 연동하기 (1) file 졸리운_곰 2024.03.17 2
145 [php] PHP - Show JSON array in html table 졸리운_곰 2024.02.18 3
144 [php] php / string을 json으로 변환 한 뒤 값 가져오기 졸리운_곰 2024.02.18 1
143 [php] Low Code Web Content Server: Making Marks on the Digital Shore. An Anecdotal View. : 로우 코드 웹 콘텐츠 서버: 디지털 해안에 흔적을 남기다. 일화적인 견해. file 졸리운_곰 2024.02.18 3
142 [php] [xampp] [php] php의 mail() 함수로 구글 이메일 보내기 / XAMPP 서버 및 aws의 EC2 / php mail function to send Gmail at XAMPP and AWS EC2 not working / Username and Password not accepted. file 졸리운_곰 2023.09.12 2
141 [php] PHP / MariaDB / 데이터베이스 값 가져와서 출력하기 졸리운_곰 2023.06.22 7
140 [php] Start Using HTML5 WebSockets Today With a PHP Server 지금 PHP 서버에서 HTML5 WebSocket 사용 시작 졸리운_곰 2023.05.09 4
139 [php] json_encode 유니코드 한글 깨짐 해결방법 졸리운_곰 2023.02.04 12
138 PHP 카운터 만들기-[1] 졸리운_곰 2022.07.20 15
137 PHP로 카운터 만들기 졸리운_곰 2022.07.20 19
136 How To Build A Rest API Using PHP file 졸리운_곰 2022.07.15 16
» PHP REST API Authentication Using JWT file 졸리운_곰 2022.07.15 13
134 [PHP] JWT 구현하기 졸리운_곰 2022.07.15 599
133 [php] Coppermine PHP로 제작된 "웹 갤러리" 프로그램임. 상당히 잘 만들어진 것같아 졸리운_곰 2021.07.04 35
132 [php] imagick php 7.3 windows 설치하기 졸리운_곰 2021.07.04 50
131 [php] simple Rest API : Build a Simple REST API in PHP file 졸리운_곰 2021.05.31 20
130 [php][php 수학][php 수치해석] MathPHP - Powerful Modern Math Library for PHP file 졸리운_곰 2021.05.03 20
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED