├── 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 |