php-simple-jwt/src/JWTToken.php

150 lines
3.9 KiB
PHP

<?php
namespace NoccyLabs\SimpleJWT;
use NoccyLabs\SimpleJWT\Collection\PropertyBag;
use NoccyLabs\SimpleJWT\Key\KeyInterface;
/**
*
*
*
*
* @property-read PropertyBag $header
* @property-read PropertyBag $claims
*/
class JWTToken
{
/** @var PropertyBag */
private $header;
/** @var PropertyBag */
private $claims;
/** @var KeyInterface */
private $key;
/** @var bool */
private $valid;
/** @var bool */
private $generated;
/**
* Constructor
*
*
* @param KeyInterface $key The key used to sign the token
* @param string|null $token Token data
*/
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);
$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;
}
}