Skip to content

Commit e9cff73

Browse files
authored
Merge pull request #14 from eschricker/feature/php8-lcobucci4-support
Migrated pull request tymondesigns/jwt-auth#2117
2 parents 29c8c69 + 43e62cd commit e9cff73

File tree

4 files changed

+215
-77
lines changed

4 files changed

+215
-77
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"illuminate/database": "^8.61",
3535
"illuminate/http": "^5.2|^6|^7|^8",
3636
"illuminate/support": "^5.2|^6|^7|^8",
37-
"lcobucci/jwt": "<3.4",
37+
"lcobucci/jwt": "^4.0",
3838
"namshi/jose": "^7.0",
3939
"nesbot/carbon": "^1.0|^2.0"
4040
},

src/Providers/AbstractServiceProvider.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
namespace PHPOpenSourceSaver\JWTAuth\Providers;
1313

1414
use Illuminate\Support\ServiceProvider;
15-
use Lcobucci\JWT\Builder as JWTBuilder;
16-
use Lcobucci\JWT\Parser as JWTParser;
1715
use Namshi\JOSE\JWS;
1816
use PHPOpenSourceSaver\JWTAuth\Blacklist;
1917
use PHPOpenSourceSaver\JWTAuth\Claims\Factory as ClaimFactory;
@@ -167,8 +165,6 @@ protected function registerLcobucciProvider()
167165
{
168166
$this->app->singleton('tymon.jwt.provider.jwt.lcobucci', function ($app) {
169167
return new Lcobucci(
170-
new JWTBuilder(),
171-
new JWTParser(),
172168
$this->config('secret'),
173169
$this->config('algo'),
174170
$this->config('keys')

src/Providers/JWT/Lcobucci.php

Lines changed: 112 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,23 @@
1414
use Exception;
1515
use Illuminate\Support\Collection;
1616
use Lcobucci\JWT\Builder;
17-
use Lcobucci\JWT\Parser;
17+
use Lcobucci\JWT\Configuration;
1818
use Lcobucci\JWT\Signer\Ecdsa;
1919
use Lcobucci\JWT\Signer\Ecdsa\Sha256 as ES256;
2020
use Lcobucci\JWT\Signer\Ecdsa\Sha384 as ES384;
2121
use Lcobucci\JWT\Signer\Ecdsa\Sha512 as ES512;
2222
use Lcobucci\JWT\Signer\Hmac\Sha256 as HS256;
2323
use Lcobucci\JWT\Signer\Hmac\Sha384 as HS384;
2424
use Lcobucci\JWT\Signer\Hmac\Sha512 as HS512;
25-
use Lcobucci\JWT\Signer\Keychain;
25+
use Lcobucci\JWT\Signer\Key\InMemory;
26+
use Lcobucci\JWT\Signer;
27+
use Lcobucci\JWT\Signer\Key;
2628
use Lcobucci\JWT\Signer\Rsa;
2729
use Lcobucci\JWT\Signer\Rsa\Sha256 as RS256;
2830
use Lcobucci\JWT\Signer\Rsa\Sha384 as RS384;
2931
use Lcobucci\JWT\Signer\Rsa\Sha512 as RS512;
32+
use Lcobucci\JWT\Token\RegisteredClaims;
33+
use Lcobucci\JWT\Validation\Constraint\SignedWith;
3034
use ReflectionClass;
3135
use PHPOpenSourceSaver\JWTAuth\Contracts\Providers\JWT;
3236
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
@@ -35,42 +39,68 @@
3539
class Lcobucci extends Provider implements JWT
3640
{
3741
/**
38-
* The Builder instance.
42+
* The builder instance.
3943
*
40-
* @var \Lcobucci\JWT\Builder
44+
* @var Builder
4145
*/
4246
protected $builder;
4347

4448
/**
45-
* The Parser instance.
49+
* The configuration instance.
4650
*
47-
* @var \Lcobucci\JWT\Parser
51+
* @var Configuration
4852
*/
49-
protected $parser;
53+
protected $config;
54+
55+
/**
56+
* The Signer instance.
57+
*
58+
* @var Signer
59+
*/
60+
protected $signer;
5061

5162
/**
5263
* Create the Lcobucci provider.
5364
*
54-
* @param \Lcobucci\JWT\Builder $builder
55-
* @param \Lcobucci\JWT\Parser $parser
5665
* @param string $secret
5766
* @param string $algo
5867
* @param array $keys
68+
* @param Configuration $config Optional, to pass an existing configuration to be used.
5969
*
6070
* @return void
6171
*/
6272
public function __construct(
63-
Builder $builder,
64-
Parser $parser,
6573
$secret,
6674
$algo,
67-
array $keys
75+
array $keys,
76+
$config = null
6877
) {
6978
parent::__construct($secret, $algo, $keys);
7079

71-
$this->builder = $builder;
72-
$this->parser = $parser;
7380
$this->signer = $this->getSigner();
81+
82+
if (!is_null($config)) {
83+
$this->config = $config;
84+
} elseif ($this->isAsymmetric()) {
85+
$this->config = Configuration::forAsymmetricSigner($this->signer, $this->getSigningKey(), $this->getVerificationKey());
86+
} else {
87+
$this->config = Configuration::forSymmetricSigner($this->signer, InMemory::plainText($this->getSecret()));
88+
}
89+
if (!count($this->config->validationConstraints())) {
90+
$this->config->setValidationConstraints(
91+
new SignedWith($this->signer, $this->getVerificationKey()),
92+
);
93+
}
94+
}
95+
96+
/**
97+
* Gets the {@see $config} attribute.
98+
*
99+
* @return Configuration
100+
*/
101+
public function getConfig()
102+
{
103+
return $this->config;
74104
}
75105

76106
/**
@@ -101,19 +131,18 @@ public function __construct(
101131
*/
102132
public function encode(array $payload)
103133
{
104-
// Remove the signature on the builder instance first.
105-
$this->builder->unsign();
134+
$this->builder = null;
135+
$this->builder = $this->config->builder();
106136

107137
try {
108138
foreach ($payload as $key => $value) {
109-
$this->builder->set($key, $value);
139+
$this->addClaim($key, $value);
110140
}
111-
$this->builder->sign($this->signer, $this->getSigningKey());
141+
142+
return $this->builder->getToken($this->config->signer(), $this->config->signingKey())->toString();
112143
} catch (Exception $e) {
113-
throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
144+
throw new JWTException('Could not create token: ' . $e->getMessage(), $e->getCode(), $e);
114145
}
115-
116-
return (string) $this->builder->getToken();
117146
}
118147

119148
/**
@@ -128,20 +157,66 @@ public function encode(array $payload)
128157
public function decode($token)
129158
{
130159
try {
131-
$jwt = $this->parser->parse($token);
160+
$jwt = $this->config->parser()->parse($token);
132161
} catch (Exception $e) {
133-
throw new TokenInvalidException('Could not decode token: '.$e->getMessage(), $e->getCode(), $e);
162+
throw new TokenInvalidException('Could not decode token: ' . $e->getMessage(), $e->getCode(), $e);
134163
}
135164

136-
if (! $jwt->verify($this->signer, $this->getVerificationKey())) {
165+
if (!$this->config->validator()->validate($jwt, ...$this->config->validationConstraints())) {
137166
throw new TokenInvalidException('Token Signature could not be verified.');
138167
}
139168

140-
return (new Collection($jwt->getClaims()))->map(function ($claim) {
141-
return is_object($claim) ? $claim->getValue() : $claim;
169+
return (new Collection($jwt->claims()->all()))->map(function ($claim) {
170+
if (is_a($claim, \DateTimeImmutable::class)) {
171+
return $claim->getTimestamp();
172+
}
173+
if (is_object($claim) && method_exists($claim, 'getValue')) {
174+
return $claim->getValue();
175+
}
176+
177+
return $claim;
142178
})->toArray();
143179
}
144180

181+
/**
182+
* Adds a claim to the {@see $config}.
183+
*
184+
* @param string $key
185+
* @param mixed $value
186+
*/
187+
protected function addClaim($key, $value)
188+
{
189+
if (!isset($this->builder)) {
190+
$this->builder = $this->config->builder();
191+
}
192+
193+
switch ($key) {
194+
case RegisteredClaims::ID:
195+
$this->builder->identifiedBy($value);
196+
break;
197+
case RegisteredClaims::EXPIRATION_TIME:
198+
$this->builder->expiresAt(\DateTimeImmutable::createFromFormat('U', $value));
199+
break;
200+
case RegisteredClaims::NOT_BEFORE:
201+
$this->builder->canOnlyBeUsedAfter(\DateTimeImmutable::createFromFormat('U', $value));
202+
break;
203+
case RegisteredClaims::ISSUED_AT:
204+
$this->builder->issuedAt(\DateTimeImmutable::createFromFormat('U', $value));
205+
break;
206+
case RegisteredClaims::ISSUER:
207+
$this->builder->issuedBy($value);
208+
break;
209+
case RegisteredClaims::AUDIENCE:
210+
$this->builder->permittedFor($value);
211+
break;
212+
case RegisteredClaims::SUBJECT:
213+
$this->builder->relatedTo($value);
214+
break;
215+
default:
216+
$this->builder->withClaim($key, $value);
217+
}
218+
}
219+
145220
/**
146221
* Get the signer instance.
147222
*
@@ -151,7 +226,7 @@ public function decode($token)
151226
*/
152227
protected function getSigner()
153228
{
154-
if (! array_key_exists($this->algo, $this->signers)) {
229+
if (!array_key_exists($this->algo, $this->signers)) {
155230
throw new JWTException('The given algorithm could not be found');
156231
}
157232

@@ -169,22 +244,26 @@ protected function isAsymmetric()
169244
}
170245

171246
/**
172-
* {@inheritdoc}
247+
* Get the key used to sign the tokens.
248+
*
249+
* @return Key|string
173250
*/
174251
protected function getSigningKey()
175252
{
176253
return $this->isAsymmetric() ?
177-
(new Keychain())->getPrivateKey($this->getPrivateKey(), $this->getPassphrase()) :
178-
$this->getSecret();
254+
InMemory::plainText($this->getPrivateKey(), $this->getPassphrase() ?? '') :
255+
InMemory::plainText($this->getSecret());
179256
}
180257

181258
/**
182-
* {@inheritdoc}
259+
* Get the key used to verify the tokens.
260+
*
261+
* @return Key|string
183262
*/
184263
protected function getVerificationKey()
185264
{
186265
return $this->isAsymmetric() ?
187-
(new Keychain())->getPublicKey($this->getPublicKey()) :
188-
$this->getSecret();
266+
InMemory::plainText($this->getPublicKey()) :
267+
InMemory::plainText($this->getSecret());
189268
}
190269
}

0 commit comments

Comments
 (0)