1: <?php
2: /*
3: You may not change or alter any portion of this comment or credits
4: of supporting developers from this source code or any supporting source code
5: which is considered copyrighted (c) material of the original comment or credit authors.
6:
7: This program is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY; without even the implied warranty of
9: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10: */
11:
12: namespace Xmf\Jwt;
13:
14: use Firebase\JWT\JWT;
15: use Firebase\JWT\Key;
16: use Xmf\Key\KeyAbstract;
17:
18: /**
19: * Basic JSON Web Token support
20: *
21: * @category Xmf\Jwt\JsonWebToken
22: * @package Xmf
23: * @author Richard Griffith <richard@geekwright.com>
24: * @copyright 2018-2023 XOOPS Project (https://xoops.org)
25: * @license GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
26: * @link https://xoops.org
27: */
28: class JsonWebToken
29: {
30: /**
31: * @var KeyAbstract
32: */
33: protected $key;
34:
35: /**
36: * @var string
37: */
38: protected $algorithm = 'HS256';
39:
40: /**
41: * @var array
42: */
43: protected $claims = array();
44:
45: /**
46: * JsonWebToken constructor.
47: *
48: * @param KeyAbstract $key key for signing/validating
49: * @param string $algorithm algorithm to use for signing/validating
50: */
51: public function __construct(KeyAbstract $key, $algorithm = 'HS256')
52: {
53: $this->key = $key;
54: $this->setAlgorithm($algorithm);
55: }
56:
57: /**
58: * @param string $algorithm algorithm to use for signing/validating
59: *
60: * @return JsonWebToken
61: *
62: * @throws \DomainException
63: */
64: public function setAlgorithm($algorithm)
65: {
66: if (array_key_exists($algorithm, JWT::$supported_algs)) {
67: $this->algorithm = $algorithm;
68: return $this;
69: }
70: throw new \DomainException('Algorithm not supported');
71: }
72:
73: /**
74: * Decode a JWT string, validating signature and well defined registered claims,
75: * and optionally validate against a list of supplied claims
76: *
77: * @param string $jwtString string containing the JWT to decode
78: * @param array|\Traversable $assertClaims associative array, claim => value, of claims to assert
79: *
80: * @return object|false
81: */
82: public function decode($jwtString, $assertClaims = array())
83: {
84: try {
85: $values = JWT::decode($jwtString, new Key($this->key->getVerifying(), $this->algorithm));
86: } catch (\Exception $e) {
87: trigger_error($e->getMessage(), E_USER_NOTICE);
88: return false;
89: }
90: foreach ($assertClaims as $claim => $assert) {
91: if (!property_exists($values, $claim)) {
92: return false;
93: }
94:
95: if ($values->$claim != $assert) {
96: return false;
97: }
98: }
99: return $values;
100: }
101:
102: /**
103: * Create a signed token string for a payload
104: *
105: * @param array|\ArrayObject $payload traversable set of claims, claim => value
106: * @param int $expirationOffset seconds from now that token will expire. If not specified,
107: * an "exp" claim will not be added or updated
108: *
109: * @return string encoded and signed jwt string
110: *
111: * @throws \DomainException;
112: * @throws \InvalidArgumentException;
113: * @throws \UnexpectedValueException;
114: */
115: public function create($payload, $expirationOffset = 0)
116: {
117: if ((int) $expirationOffset > 0) {
118: $payload['exp'] = time() + (int) $expirationOffset;
119: }
120: $value = JWT::encode($payload, $this->key->getSigning(), $this->algorithm);
121: return $value;
122: }
123: }
124: