2021-02-11 13:22:51 +01:00
|
|
|
<?php
|
|
|
|
|
2023-04-09 02:40:21 +02:00
|
|
|
namespace NoccyLabs\SimpleJWT;
|
2021-02-11 13:22:51 +01:00
|
|
|
|
2023-04-09 02:40:21 +02:00
|
|
|
use NoccyLabs\SimpleJWT\Collection\PropertyBag;
|
|
|
|
use NoccyLabs\SimpleJWT\Key\KeyInterface;
|
2021-02-11 13:22:51 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @property-read header PropertyBag
|
|
|
|
* @property-read claim PropertyBag
|
|
|
|
*/
|
2023-04-09 02:40:21 +02:00
|
|
|
class JWTToken
|
2021-02-11 13:22:51 +01:00
|
|
|
{
|
|
|
|
/** @var PropertyBag */
|
|
|
|
private $header;
|
|
|
|
/** @var PropertyBag */
|
|
|
|
private $claims;
|
|
|
|
/** @var KeyInterface */
|
|
|
|
private $key;
|
|
|
|
/** @var bool */
|
|
|
|
private $valid;
|
|
|
|
/** @var bool */
|
|
|
|
private $generated;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param KeyInterface The key used to sign the token
|
|
|
|
*/
|
|
|
|
public function __construct(KeyInterface $key, ?string $token=null)
|
|
|
|
{
|
|
|
|
$this->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);
|
2023-04-09 02:40:21 +02:00
|
|
|
$hash = JWTUtil::encode(hash_hmac("sha256", $header.".".$payload, $this->key->getBinaryKey(), true));
|
2021-02-11 13:22:51 +01:00
|
|
|
if ($signature == $hash) {
|
|
|
|
$this->valid = true;
|
|
|
|
}
|
|
|
|
|
2023-04-09 02:40:21 +02:00
|
|
|
$this->header = new PropertyBag(json_decode(JWTUtil::decode($header), true));
|
|
|
|
$this->claims = new PropertyBag(json_decode(JWTUtil::decode($payload), true));
|
2021-02-11 13:22:51 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
$this->header->set('exp', time() + (intval($match[1]) * $fact));
|
|
|
|
} else {
|
|
|
|
throw new \InvalidArgumentException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getSignedToken(): string
|
|
|
|
{
|
2023-04-09 02:40:21 +02:00
|
|
|
$header = JWTUtil::encode($this->header->getJson());
|
|
|
|
$payload = JWTUtil::encode($this->claims->getJson());
|
|
|
|
$hash = JWTUtil::encode(hash_hmac("sha256", $header.".".$payload, $this->key->getBinaryKey(), true));
|
2021-02-11 13:22:51 +01:00
|
|
|
return $header.".".$payload.".".$hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|