1010use Lcobucci \JWT \Decoder ;
1111use Lcobucci \JWT \Encoder ;
1212use Lcobucci \JWT \Encoding \CannotDecodeContent ;
13+ use Lcobucci \JWT \Encoding \JoseEncoder ;
1314use Lcobucci \JWT \Parser ;
1415use Lcobucci \JWT \Signer ;
1516use Lcobucci \JWT \Token ;
2627use function is_callable ;
2728use function is_string ;
2829use function reset ;
29- use function strpos ;
30+ use function str_starts_with ;
3031
3132/**
32- * JSON Web Token implementation based on lcobucci/jwt library v4 .
33+ * JSON Web Token implementation based on lcobucci/jwt library v5 .
3334 * @see https://github.com/lcobucci/jwt
3435 *
3536 * @author Paweł Bizley Brzozowski <[email protected] > since 2.0 (fork) @@ -50,7 +51,6 @@ class Jwt extends Component
5051 public const BLAKE2B = 'BLAKE2B ' ;
5152
5253 public const STORE_IN_MEMORY = 'in_memory ' ;
53- public const STORE_LOCAL_FILE_REFERENCE = 'local_file_reference ' ; // deprecated since 3.2.0, will be removed in 4.0.0
5454
5555 public const METHOD_PLAIN = 'plain ' ;
5656 public const METHOD_BASE64 = 'base64 ' ;
@@ -69,26 +69,20 @@ class Jwt extends Component
6969 * This can be a simple string, an instance of Key, or a configuration array.
7070 * The configuration takes the following array keys:
7171 * - 'key' => Key's value or path to the key file.
72- * - 'store' => Either `Jwt::STORE_IN_MEMORY` or `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated) -
73- * whether to keep the key in the memory or as a reference to a local file.
7472 * - 'method' => `Jwt::METHOD_PLAIN`, `Jwt::METHOD_BASE64`, or `Jwt::METHOD_FILE` - whether the key is a plain
7573 * text, base64 encoded text, or a file.
76- * In case the 'store' is set to `Jwt::STORE_LOCAL_FILE_REFERENCE` (deprecated), only
77- * `Jwt::METHOD_FILE` method is available.
7874 * - 'passphrase' => Key's passphrase.
7975 * In case a simple string is provided (and it does not start with 'file://' or '@') the following configuration
8076 * is assumed:
8177 * [
8278 * 'key' => // the original given value,
83- * 'store' => Jwt::STORE_IN_MEMORY,
8479 * 'method' => Jwt::METHOD_PLAIN,
8580 * 'passphrase' => '',
8681 * ]
8782 * In case a simple string is provided and it does start with 'file://' (direct file path) or '@' (Yii alias)
8883 * the following configuration is assumed:
8984 * [
9085 * 'key' => // the original given value,
91- * 'store' => Jwt::STORE_IN_MEMORY,
9286 * 'method' => Jwt::METHOD_FILE,
9387 * 'passphrase' => '',
9488 * ]
@@ -107,12 +101,11 @@ class Jwt extends Component
107101 public $ verifyingKey = '' ;
108102
109103 /**
110- * @var string|Signer|null Signer ID or Signer instance to be used for signing/verifying.
111- * See $signers for available values. In case it's not set, no algorithm will be used, which may be handy if you
112- * want to do some testing, but it's NOT recommended for production environments.
104+ * @var string|Signer Signer ID or Signer instance to be used for signing/verifying.
105+ * See $signers for available values. Since 4.0.0 it cannot be empty anymore.
113106 * @since 3.0.0
114107 */
115- public $ signer ;
108+ public $ signer = '' ;
116109
117110 /**
118111 * @var array<string, string[]> Default signers configuration. When instantiated it will use selected array to
@@ -192,31 +185,27 @@ public function init(): void
192185 {
193186 parent ::init ();
194187
195- if ($ this ->signer === null ) {
196- $ this ->configuration = Configuration::forUnsecuredSigner ($ this ->prepareEncoder (), $ this ->prepareDecoder ());
188+ $ signerId = $ this ->signer ;
189+ if ($ this ->signer instanceof Signer) {
190+ $ signerId = $ this ->signer ->algorithmId ();
191+ }
192+ if (in_array ($ signerId , $ this ->algorithmTypes [self ::SYMMETRIC ], true )) {
193+ $ this ->configuration = Configuration::forSymmetricSigner (
194+ $ this ->prepareSigner ($ this ->signer ),
195+ $ this ->prepareKey ($ this ->signingKey ),
196+ $ this ->prepareEncoder (),
197+ $ this ->prepareDecoder ()
198+ );
199+ } elseif (in_array ($ signerId , $ this ->algorithmTypes [self ::ASYMMETRIC ], true )) {
200+ $ this ->configuration = Configuration::forAsymmetricSigner (
201+ $ this ->prepareSigner ($ this ->signer ),
202+ $ this ->prepareKey ($ this ->signingKey ),
203+ $ this ->prepareKey ($ this ->verifyingKey ),
204+ $ this ->prepareEncoder (),
205+ $ this ->prepareDecoder ()
206+ );
197207 } else {
198- $ signerId = $ this ->signer ;
199- if ($ this ->signer instanceof Signer) {
200- $ signerId = $ this ->signer ->algorithmId ();
201- }
202- if (in_array ($ signerId , $ this ->algorithmTypes [self ::SYMMETRIC ], true )) {
203- $ this ->configuration = Configuration::forSymmetricSigner (
204- $ this ->prepareSigner ($ this ->signer ),
205- $ this ->prepareKey ($ this ->signingKey ),
206- $ this ->prepareEncoder (),
207- $ this ->prepareDecoder ()
208- );
209- } elseif (in_array ($ signerId , $ this ->algorithmTypes [self ::ASYMMETRIC ], true )) {
210- $ this ->configuration = Configuration::forAsymmetricSigner (
211- $ this ->prepareSigner ($ this ->signer ),
212- $ this ->prepareKey ($ this ->signingKey ),
213- $ this ->prepareKey ($ this ->verifyingKey ),
214- $ this ->prepareEncoder (),
215- $ this ->prepareDecoder ()
216- );
217- } else {
218- throw new InvalidConfigException ('Invalid signer ID! ' );
219- }
208+ throw new InvalidConfigException ('Invalid signer ID! ' );
220209 }
221210 }
222211
@@ -251,6 +240,7 @@ public function getConfiguration(): Configuration
251240
252241 /**
253242 * Since 3.0.0 this method is using different signature.
243+ * Please note that since 4.0.0 Builder object is immutable.
254244 * @see https://lcobucci-jwt.readthedocs.io/en/latest/issuing-tokens/ for details of using the builder.
255245 * @throws InvalidConfigException
256246 */
@@ -270,6 +260,7 @@ public function getParser(): Parser
270260 }
271261
272262 /**
263+ * @param non-empty-string $jwt
273264 * @throws CannotDecodeContent When something goes wrong while decoding.
274265 * @throws Token\InvalidTokenStructure When token string structure is invalid.
275266 * @throws Token\UnsupportedHeaderFound When parsed token has an unsupported header.
@@ -284,7 +275,7 @@ public function parse(string $jwt): Token
284275 /**
285276 * This method goes through every single constraint in the set, groups all the violations, and throws an exception
286277 * with the grouped violations.
287- * @param string|Token $jwt JWT string or instance of Token
278+ * @param non-empty- string|Token $jwt JWT string or instance of Token
288279 * @throws Validation\RequiredConstraintsViolated When constraint is violated
289280 * @throws Validation\NoConstraintsGiven When no constraints are provided
290281 * @throws InvalidConfigException
@@ -300,7 +291,7 @@ public function assert($jwt): void
300291
301292 /**
302293 * This method return false on first constraint violation
303- * @param string|Token $jwt JWT string or instance of Token
294+ * @param non-empty- string|Token $jwt JWT string or instance of Token
304295 * @throws InvalidConfigException
305296 * @since 3.0.0
306297 */
@@ -331,22 +322,19 @@ private function prepareKey($key): Signer\Key
331322 if ($ key === '' ) {
332323 throw new InvalidConfigException ('Empty string used as a key configuration! ' );
333324 }
334- if (strpos ($ key , '@ ' ) === 0 ) {
325+ if (str_starts_with ($ key , '@ ' )) {
335326 $ keyConfig = [
336327 self ::KEY => Yii::getAlias ($ key ),
337- self ::STORE => self ::STORE_IN_MEMORY ,
338328 self ::METHOD => self ::METHOD_FILE ,
339329 ];
340- } elseif (strpos ($ key , 'file:// ' ) === 0 ) {
330+ } elseif (str_starts_with ($ key , 'file:// ' )) {
341331 $ keyConfig = [
342332 self ::KEY => $ key ,
343- self ::STORE => self ::STORE_IN_MEMORY ,
344333 self ::METHOD => self ::METHOD_FILE ,
345334 ];
346335 } else {
347336 $ keyConfig = [
348337 self ::KEY => $ key ,
349- self ::STORE => self ::STORE_IN_MEMORY ,
350338 self ::METHOD => self ::METHOD_PLAIN ,
351339 ];
352340 }
@@ -357,42 +345,27 @@ private function prepareKey($key): Signer\Key
357345 }
358346
359347 $ value = $ keyConfig [self ::KEY ] ?? '' ;
360- $ store = $ keyConfig [self ::STORE ] ?? self ::STORE_IN_MEMORY ;
361348 $ method = $ keyConfig [self ::METHOD ] ?? self ::METHOD_PLAIN ;
362349 $ passphrase = $ keyConfig [self ::PASSPHRASE ] ?? '' ;
363350
364- if (!is_string ($ value )) {
351+ if (!is_string ($ value ) || $ value === '' ) {
365352 throw new InvalidConfigException ('Invalid key value! ' );
366353 }
367- if (!in_array ($ store , [self ::STORE_IN_MEMORY , self ::STORE_LOCAL_FILE_REFERENCE ], true )) {
368- throw new InvalidConfigException ('Invalid key store! ' );
369- }
370354 if (!in_array ($ method , [self ::METHOD_PLAIN , self ::METHOD_BASE64 , self ::METHOD_FILE ], true )) {
371355 throw new InvalidConfigException ('Invalid key method! ' );
372356 }
373357 if (!is_string ($ passphrase )) {
374358 throw new InvalidConfigException ('Invalid key passphrase! ' );
375359 }
376360
377- if ($ store === self ::STORE_IN_MEMORY ) {
378- if ($ value === '' ) {
379- return Signer \Key \InMemory::empty ();
380- }
381- if ($ method === self ::METHOD_BASE64 ) {
382- return Signer \Key \InMemory::base64Encoded ($ value , $ passphrase );
383- }
384- if ($ method === self ::METHOD_FILE ) {
385- return Signer \Key \InMemory::file ($ value , $ passphrase );
386- }
387-
388- return Signer \Key \InMemory::plainText ($ value , $ passphrase );
361+ if ($ method === self ::METHOD_BASE64 ) {
362+ return Signer \Key \InMemory::base64Encoded ($ value , $ passphrase );
389363 }
390-
391- if ($ method !== self ::METHOD_FILE ) {
392- throw new InvalidConfigException ('Invalid key store and method combination! ' );
364+ if ($ method === self ::METHOD_FILE ) {
365+ return Signer \Key \InMemory::file ($ value , $ passphrase );
393366 }
394367
395- return Signer \Key \InMemory::file ($ value , $ passphrase );
368+ return Signer \Key \InMemory::plainText ($ value , $ passphrase );
396369 }
397370
398371 /**
@@ -454,10 +427,10 @@ private function prepareValidationConstraints(): array
454427 /**
455428 * @throws InvalidConfigException
456429 */
457- private function prepareEncoder (): ? Encoder
430+ private function prepareEncoder (): Encoder
458431 {
459432 if ($ this ->encoder === null ) {
460- return null ;
433+ return new JoseEncoder () ;
461434 }
462435
463436 /** @var Encoder $encoder */
@@ -469,10 +442,10 @@ private function prepareEncoder(): ?Encoder
469442 /**
470443 * @throws InvalidConfigException
471444 */
472- private function prepareDecoder (): ? Decoder
445+ private function prepareDecoder (): Decoder
473446 {
474447 if ($ this ->decoder === null ) {
475- return null ;
448+ return new JoseEncoder () ;
476449 }
477450
478451 /** @var Decoder $decoder */
0 commit comments