An Interest In:
Web News this Week
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
- April 20, 2024
- April 19, 2024
- April 18, 2024
JSON Web Tokens without Firebase JWT
I have created a few tutorials on how to use Firebase JWT to create and use JSON Web Tokens, but I decided to try to do it without a framework, using just PHP. In this article, you can see how I created my own simple JWT generator.
View This On YouTube
Creating Our Class
class JWT { private $headers; private $secret; public function __construct() { $this->headers = [ 'alg' => 'HS256', // we are using a SHA256 algorithm 'typ' => 'JWT', // JWT type 'iss' => 'jwt.local', // token issuer 'aud' => 'example.com' // token audience ]; $this->secret = 'thisIsASecret'; }}
Generate A Token
Within this class, we will create our generate function. this function will generate our token to be used against our validator.
public function generate(array $payload): string{ $headers = $this->encode(json_encode($this->headers)); // encode headers $payload["exp"] = time() + 60; // add expiration to payload $payload = $this->encode(json_encode($payload)); // encode payload $signature = hash_hmac('SHA256', "$headers.$payload", $this->secret, true); // create SHA256 signature $signature = $this->encode($signature); // encode signature return "$headers.$payload.$signature";}
Within our generate function, we reference a encode function. This function will simply base64 encode our strings to be used by the token.
private function encode(string $str): string{ return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); // base64 encode string}
Validate Our Token
In this function, we take the generated token, and validate the strings, the encoding, and finally the time. I have it set for 1 minute so the token will expire after 1 minute to ensure it is used for a purpose.
public function is_valid(string $jwt): bool{ $token = explode('.', $jwt); // explode token based on JWT breaks if (!isset($token[1]) && !isset($token[2])) { return false; // fails if the header and payload is not set } $headers = base64_decode($token[0]); // decode header, create variable $payload = base64_decode($token[1]); // decode payload, create variable $clientSignature = $token[2]; // create variable for signature if (!json_decode($payload)) { return false; // fails if payload does not decode } if ((json_decode($payload)->exp - time()) < 0) { return false; // fails if expiration is greater than 0, setup for 1 minute } if (isset(json_decode($payload)->iss)) { if (json_decode($headers)->iss != json_decode($payload)->iss) { return false; // fails if issuers are not the same } } else { return false; // fails if issuer is not set } if (isset(json_decode($payload)->aud)) { if (json_decode($headers)->aud != json_decode($payload)->aud) { return false; // fails if audiences are not the same } } else { return false; // fails if audience is not set } $base64_header = $this->encode($headers); $base64_payload = $this->encode($payload); $signature = hash_hmac('SHA256', $base64_header . "." . $base64_payload, $this->secret, true); $base64_signature = $this->encode($signature); return ($base64_signature === $clientSignature);}
Putting It All Together
class JWT{ private $headers; private $secret; public function __construct() { $this->headers = [ 'alg' => 'HS256', // we are using a SHA256 algorithm 'typ' => 'JWT', // JWT type 'iss' => 'jwt.local', // token issuer 'aud' => 'example.com' // token audience ]; $this->secret = 'thisIsASecret'; // change this to your secret code } public function generate(array $payload): string { $headers = $this->encode(json_encode($this->headers)); // encode headers $payload["exp"] = time() + 60; // add expiration to payload $payload = $this->encode(json_encode($payload)); // encode payload $signature = hash_hmac('SHA256', "$headers.$payload", $this->secret, true); // create SHA256 signature $signature = $this->encode($signature); // encode signature return "$headers.$payload.$signature"; } private function encode(string $str): string { return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); // base64 encode string } public function is_valid(string $jwt): bool { $token = explode('.', $jwt); // explode token based on JWT breaks if (!isset($token[1]) && !isset($token[2])) { return false; // fails if the header and payload is not set } $headers = base64_decode($token[0]); // decode header, create variable $payload = base64_decode($token[1]); // decode payload, create variable $clientSignature = $token[2]; // create variable for signature if (!json_decode($payload)) { return false; // fails if payload does not decode } if ((json_decode($payload)->exp - time()) < 0) { return false; // fails if expiration is greater than 0, setup for 1 minute } if (isset(json_decode($payload)->iss)) { if (json_decode($headers)->iss != json_decode($payload)->iss) { return false; // fails if issuers are not the same } } else { return false; // fails if issuer is not set } if (isset(json_decode($payload)->aud)) { if (json_decode($headers)->aud != json_decode($payload)->aud) { return false; // fails if audiences are not the same } } else { return false; // fails if audience is not set } $base64_header = $this->encode($headers); $base64_payload = $this->encode($payload); $signature = hash_hmac('SHA256', $base64_header . "." . $base64_payload, $this->secret, true); $base64_signature = $this->encode($signature); return ($base64_signature === $clientSignature); }}
Conclusion
It is a simple project, but works as intended. I have used Firebase JWT in the past but sometimes you just need a simple solution without having to import and entire library. I hope this helps for your next small project. You can download the class on my GitHub or subscribe on YouTube for more tutorials.
Original Link: https://dev.to/thedevdrawer/json-web-tokens-without-firebase-jwt-3mop
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To