├── README.md ├── classes └── JWT.php ├── functions.php └── index.php /README.md: -------------------------------------------------------------------------------- 1 | # PHP JSON Web Token without Firebase JWT 2 | Learn how to create your own JSON web tokens without Firebase JWT or any other JWT frameworks. In this tutorial, we will learn how to create your own JWT class in PHP. 3 | 4 | JWT or JSON Web Tokens is is a digitally signed, trusted connection between two services (usually an API and a webserver). With JWT, you can allow access to external sources with the knowledge that the request is valid and made intentionally. This can help you develop your own API as laid out in my 33rd video called "Add Security and JWT Tokenization to Your PHP REST API, Part 6 - #33". You can find that here: [https://youtu.be/t43DRY3Ee9w](https://youtu.be/t43DRY3Ee9w) 5 | 6 | In this tutorial, we will be building our own JWT generator instead of using a framework like Firebase JWT (as we did in the other video). You can easily create your own JWT authentication and run it against your API to validate users or information. Without using a framework, we open our code a bit to allow us to customize it more as we see fit. 7 | 8 | This type of project is for smaller APIs, but should get you through most of what you would need if developing something in-house or just to learn how they work. 9 | 10 | View the video: [https://youtu.be/WWAjqDupyqU](https://youtu.be/WWAjqDupyqU) 11 | 12 | -------------------------------------------------------------------------------- /classes/JWT.php: -------------------------------------------------------------------------------- 1 | headers = [ 21 | 'alg' => 'HS256', // we are using a SHA256 algorithm 22 | 'typ' => 'JWT', // JWT type 23 | 'iss' => 'jwt.local', // token issuer 24 | 'aud' => 'example.com' // token audience 25 | ]; 26 | $this->secret = 'thisIsASecret'; // change this to your secret code 27 | } 28 | 29 | /** 30 | * Generate JWT using a payload. 31 | * 32 | * @param array $payload 33 | * @return string 34 | */ 35 | public function generate(array $payload): string 36 | { 37 | $headers = $this->encode(json_encode($this->headers)); // encode headers 38 | $payload["exp"] = time() + 60; // add expiration to payload 39 | $payload = $this->encode(json_encode($payload)); // encode payload 40 | $signature = hash_hmac('SHA256', "$headers.$payload", $this->secret, true); // create SHA256 signature 41 | $signature = $this->encode($signature); // encode signature 42 | 43 | return "$headers.$payload.$signature"; 44 | } 45 | 46 | /** 47 | * Encode JWT using base64. 48 | * 49 | * @param string $str 50 | * @return string 51 | */ 52 | private function encode(string $str): string 53 | { 54 | return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); // base64 encode string 55 | } 56 | 57 | /** 58 | * Check if JWT is valid, return true | false. 59 | * 60 | * @param string $jwt 61 | * @return boolean 62 | */ 63 | public function is_valid(string $jwt): bool 64 | { 65 | $token = explode('.', $jwt); // explode token based on JWT breaks 66 | if (!isset($token[1]) && !isset($token[2])) { 67 | return false; // fails if the header and payload is not set 68 | } 69 | $headers = base64_decode($token[0]); // decode header, create variable 70 | $payload = base64_decode($token[1]); // decode payload, create variable 71 | $clientSignature = $token[2]; // create variable for signature 72 | 73 | if (!json_decode($payload)) { 74 | return false; // fails if payload does not decode 75 | } 76 | 77 | if ((json_decode($payload)->exp - time()) < 0) { 78 | return false; // fails if expiration is greater than 0, setup for 1 minute 79 | } 80 | 81 | if (isset(json_decode($payload)->iss)) { 82 | if (json_decode($headers)->iss != json_decode($payload)->iss) { 83 | return false; // fails if issuers are not the same 84 | } 85 | } else { 86 | return false; // fails if issuer is not set 87 | } 88 | 89 | if (isset(json_decode($payload)->aud)) { 90 | if (json_decode($headers)->aud != json_decode($payload)->aud) { 91 | return false; // fails if audiences are not the same 92 | } 93 | } else { 94 | return false; // fails if audience is not set 95 | } 96 | 97 | $base64_header = $this->encode($headers); 98 | $base64_payload = $this->encode($payload); 99 | 100 | $signature = hash_hmac('SHA256', $base64_header . "." . $base64_payload, $this->secret, true); 101 | $base64_signature = $this->encode($signature); 102 | 103 | return ($base64_signature === $clientSignature); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | JWT is valid' : 'JWT is invalid') . '
'; 7 | } 8 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | JWT Tutorial 16 | 17 | 18 | 19 |

JWT Tutorial

20 | '1', 23 | 'name' => 'John Doe', 24 | 'iss' => 'jwt.local', 25 | 'aud' => 'example.com' 26 | ]; 27 | $token = $jwt->generate($payload); 28 | sample($jwt->is_valid($token)); 29 | 30 | $payload = [ 31 | 'id' => '1', 32 | 'name' => 'John Doe' 33 | ]; 34 | $token = $jwt->generate($payload); 35 | sample($jwt->is_valid($token)); 36 | 37 | sample($jwt->is_valid('test')); 38 | ?> 39 | 40 | 41 | --------------------------------------------------------------------------------