key = $key; if ($token) { $this->parseToken($token); } else { $this->header = new PropertyBag([ 'alg' => "HS256", 'typ' => "JWT", ]); $this->claims = new PropertyBag(); $this->valid = true; $this->generated = true; } } private function parseToken(string $token) { $this->generated = false; [ $header, $payload, $signature ] = explode(".", trim($token), 3); $hash = JWTUtil::encode(hash_hmac("sha256", $header.".".$payload, $this->key->getBinaryKey(), true)); if ($signature == $hash) { $this->valid = true; } $this->header = new PropertyBag(json_decode(JWTUtil::decode($header), true)); $this->claims = new PropertyBag(json_decode(JWTUtil::decode($payload), true)); if ($this->header->has('exp')) { $exp = intval($this->header->get('exp')); if ($exp <= time()) { // Invalid if expired $this->valid = false; } } } public function isValid(): bool { return $this->valid; } public function isGenerated(): bool { return $this->generated; } public function __get(string $key) { switch ($key) { case 'header': return $this->header; case 'claims': return $this->claims; } } public function addClaim(string $name, $value) { $this->claims->add($name, $value); } public function setClaim(string $name, $value) { $this->claims->set($name, $value); } public function setExpiry($expiry) { if ($expiry instanceof \DateTime) { $this->header->set('exp', $expiry->format("U")); } elseif ($expiry === null) { $this->header->delete('exp'); } elseif (is_numeric($expiry)) { if ($expiry < time()) { $this->header->set('exp', time() + $expiry); } else { $this->header->set('exp', intval($expiry)); } } elseif ($t = strtotime($expiry)) { $this->header->set('exp', $t); } elseif (preg_match('/([0-9]+)([wdhm])/', $expiry, $match)) { switch ($match[2]) { case 'w': $fact = 60 * 60 * 24 * 7; break; case 'd': $fact = 60 * 60 * 24; break; case 'h': $fact = 60 * 60; break; case 'm': $fact = 60; break; default: throw new \InvalidArgumentException(); } $this->header->set('exp', time() + (intval($match[1]) * $fact)); } else { throw new \InvalidArgumentException(); } } public function getSignedToken(): string { $header = JWTUtil::encode($this->header->getJson()); $payload = JWTUtil::encode($this->claims->getJson()); $hash = JWTUtil::encode(hash_hmac("sha256", $header.".".$payload, $this->key->getBinaryKey(), true)); return $header.".".$payload.".".$hash; } }