5use Jose\Component\Core;
6use Jose\Component\Signature;
7use Jose\Component\Signature\JWS;
8use Jose\Component\KeyManagement;
9use Jose\Component\Checker;
10use Jose\Component\Encryption;
11use Jose\Component\Encryption\JWE;
49 private $claims =
null;
56 private static $lastHeaders =
null;
63 private static $lastPayload =
null;
82 return !empty($this->jwt);
92 return !empty($this->jwe);
103 public function load($jwtString, $privateKey =
null)
108 $this->claims =
null;
110 $serializer =
new Signature\Serializer\CompactSerializer();
111 $this->jwt = $serializer->unserialize($jwtString);
112 }
catch (\Exception $e) {
117 $serializer =
new Encryption\Serializer\CompactSerializer();
118 $this->jwt = $serializer->unserialize($jwtString);
119 $ok = $this->decrypt($privateKey);
120 }
catch (\Exception $e) {
139 $headers = $this->jwe->getSharedProtectedHeader();
156 if ($this->jwt instanceof Signature\JWS) {
157 $ok = $this->jwt->getSignature(0)->hasProtectedHeaderParameter($name);
176 $value = $this->jwt->getSignature(0)->getProtectedHeaderParameter($name);
177 }
catch (\Exception $e) {
178 $value = $defaultValue;
192 if ($this->jwt instanceof Signature\JWS) {
193 $headers = $this->jwt->getSignature(0)->getProtectedHeader();
206 return self::$lastHeaders;
218 return isset($this->claims->{$name});
229 public function getClaim($name, $defaultValue =
null)
231 if ($this->hasClaim($name)) {
232 $value = $this->claims->{$name};
234 $value = $defaultValue;
247 return $this->claims;
257 return self::$lastPayload;
268 public function verify($publicKey, $jku =
null)
271 $hasPublicKey = !empty($publicKey);
273 $leeway = Jwt::$leeway;
276 $claimCheckerManager =
new Checker\ClaimCheckerManager(
278 new Checker\IssuedAtChecker($leeway),
279 new Checker\NotBeforeChecker($leeway),
280 new Checker\ExpirationTimeChecker($leeway)
283 $claimCheckerManager->check(Util::jsonDecode($this->jwt->getPayload(),
true));
284 $algorithmManager =
new Core\AlgorithmManager([
285 new Signature\Algorithm\RS256(),
286 new Signature\Algorithm\RS384(),
287 new Signature\Algorithm\RS512()
289 $jwsVerifier =
new Signature\JWSVerifier(
292 switch ($this->getHeader(
'alg')) {
296 if ($this->hasHeader(
'kid') && ((Jwt::$allowJkuHeader && $this->hasHeader(
'jku')) || (!empty($jku) && empty($publicKey)))) {
297 if (Jwt::$allowJkuHeader && $this->hasHeader(
'jku')) {
298 $jwksUrl = $this->getHeader(
'jku');
302 $jwks = $this->fetchPublicKey($jwksUrl, $this->getHeader(
'kid'));
303 $ok = $jwsVerifier->verifyWithKeySet($this->jwt, $jwks, 0);
305 $json = Util::jsonDecode($publicKey,
true);
306 if (is_null($json)) {
307 $jwk = self::getJwk($publicKey, [
'alg' => $this->getHeader(
'alg'),
'use' =>
'sig']);
309 $jwk =
new Core\JWK($json);
311 $ok = $jwsVerifier->verifyWithKey($this->jwt, $jwk, 0);
315 }
catch (\Exception $e) {
316 Util::logError($e->getMessage());
317 }
catch (\TypeError $e) {
318 Util::logError($e->getMessage());
323 } elseif ($hasPublicKey && !empty($jku)) {
326 $hasPublicKey =
false;
329 }
while (!$ok && $retry);
348 public static function sign($payload, $signatureMethod, $privateKey, $kid =
null, $jku =
null, $encryptionMethod =
null,
351 switch ($signatureMethod) {
353 $sig =
new Signature\Algorithm\RS512();
356 $sig =
new Signature\Algorithm\RS384();
359 $signatureMethod =
'RS256';
360 $sig =
new Signature\Algorithm\RS256();
363 $jwk = self::getJwk($privateKey, [
'alg' => $signatureMethod,
'use' =>
'sig']);
364 $headers = [
'typ' =>
'JWT',
'alg' => $signatureMethod];
366 $headers[
'kid'] = $kid;
368 $headers[
'jku'] = $jku;
371 $algorithmManager =
new Core\AlgorithmManager(
373 new Signature\Algorithm\RS256(),
374 new Signature\Algorithm\RS384(),
375 new Signature\Algorithm\RS512()
378 $jwsBuilder =
new Signature\JWSBuilder($algorithmManager);
379 $jsonPayload = json_encode($payload);
380 $jws = $jwsBuilder->create()
381 ->withPayload($jsonPayload)
382 ->addSignature($jwk, $headers)
384 $serializer =
new Signature\Serializer\CompactSerializer();
385 $jwt = $serializer->serialize($jws);
386 if (!empty($encryptionMethod)) {
387 if (!empty($publicKey)) {
388 $keyEnc =
'RSA-OAEP-256';
389 $jwk = self::getJwk($publicKey, [
'alg' => $keyEnc,
'use' =>
'enc',
'zip' =>
'DEF']);
390 $keyEncryptionAlgorithmManager =
new Core\AlgorithmManager([
new Encryption\Algorithm\KeyEncryption\RSAOAEP256()]);
391 $contentEncryptionAlgorithmManager =
new Core\AlgorithmManager(
393 new Encryption\Algorithm\ContentEncryption\A128CBCHS256(),
394 new Encryption\Algorithm\ContentEncryption\A192CBCHS384(),
395 new Encryption\Algorithm\ContentEncryption\A256CBCHS512(),
398 $compressionMethodManager =
new Encryption\Compression\CompressionMethodManager([
new Encryption\Compression\Deflate()]);
399 $jweBuilder =
new Encryption\JWEBuilder($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager,
400 $compressionMethodManager);
404 ->withSharedProtectedHeader([
'alg' => $keyEnc,
'enc' => $encryptionMethod,
'zip' =>
'DEF'])
407 $serializer =
new Encryption\Serializer\CompactSerializer();
408 $jwt = $serializer->serialize($jwe);
410 $errorMessage =
'No public key provided for encrypting JWT content';
411 Util::logError($errorMessage);
412 throw new \Exception($errorMessage);
415 self::$lastHeaders = $headers;
416 self::$lastPayload = $payload;
430 return FirebaseClient::generateKey($signatureMethod);
442 return FirebaseClient::getPublicKey($privateKey);
454 public static function getJWKS($pemKey, $signatureMethod, $kid)
456 $keys[
'keys'] = array();
457 $additionalValues = [
'alg' => $signatureMethod,
'use' =>
'sig'];
459 $additionalValues[
'kid'] = $kid;
462 $jwk = KeyManagement\JWKFactory::createFromKey($pemKey,
null, $additionalValues);
463 $jwk = $jwk->toPublic();
464 $rsa = KeyManagement\KeyConverter\RSAKey::createFromJWK($jwk);
465 $rsa = $rsa::toPublic($rsa);
466 $keys[
'keys'][] = $rsa->toArray();
467 }
catch (\Exception $e) {
485 private function decrypt($privateKey)
488 if ($this->jwt instanceof Encryption\JWE) {
489 $this->jwe = clone $this->jwt;
490 $keyEnc = $this->jwe->getSharedProtectedHeaderParameter(
'alg');
491 $jwk = KeyManagement\JWKFactory::createFromKey($privateKey,
null, [
'alg' => $keyEnc,
'use' =>
'enc']);
492 $keyEncryptionAlgorithmManager =
new Core\AlgorithmManager([
new Encryption\Algorithm\KeyEncryption\RSAOAEP256()]);
493 $contentEncryptionAlgorithmManager =
new Core\AlgorithmManager(
495 new Encryption\Algorithm\ContentEncryption\A128CBCHS256(),
496 new Encryption\Algorithm\ContentEncryption\A192CBCHS384(),
497 new Encryption\Algorithm\ContentEncryption\A256CBCHS512()
500 $compressionMethodManager =
new Encryption\Compression\CompressionMethodManager([
new Encryption\Compression\Deflate()]);
501 $jweDecrypter =
new Encryption\JWEDecrypter($keyEncryptionAlgorithmManager, $contentEncryptionAlgorithmManager,
502 $compressionMethodManager);
503 if ($jweDecrypter->decryptUsingKey($this->jwt, $jwk, 0)) {
505 $jwt = $this->jwt->getPayload();
506 $serializer =
new Signature\Serializer\CompactSerializer();
507 $this->jwt = $serializer->unserialize($jwt);
509 }
catch (\Exception $e) {
526 private static function getJwk($key, $additionalValues)
528 $keyValues = Util::jsonDecode($key,
true);
529 if (!is_array($keyValues)) {
530 $jwk = KeyManagement\JWKFactory::createFromKey($key,
null, $additionalValues);
532 $keyValues = array_merge($keyValues, $additionalValues);
533 $jwk =
new Core\JWK($keyValues);
547 private function fetchPublicKey($jku, $kid)
550 $http =
new HttpMessage($jku);
552 $keys = Core\Util\JsonConverter::decode($http->response);
553 foreach ($keys[
'keys'] as $id => $key) {
554 if (!isset($key[
'kid']) || ($key[
'kid'] !== $kid)) {
555 unset($keys[
'keys'][$id]);
558 $publicKey = Core\JWKSet::createFromKeyData($keys);
Class to represent an HTTP message request.
Class to represent an HTTP message request.
Class to implement the JWT interface using the Web Token JWT Framework library from https://web-token...
static getLastHeaders()
Get the value of the headers for the last signed JWT (before any encryption).
static getLastPayload()
Get the value of the payload for the last signed JWT (before any encryption).
getHeaders()
Get the value of the headers.
static getJWKS($pemKey, $signatureMethod, $kid)
Get the public JWKS from a key in PEM format.
hasJwt()
Check if a JWT is defined.
getJweHeaders()
Get the value of the JWE headers.
static getPublicKey($privateKey)
Get the public key for a private key.
load($jwtString, $privateKey=null)
Load a JWT from a string.
static generateKey($signatureMethod='RS256')
Generate a new private key in PEM format.
const SUPPORTED_ALGORITHMS
Supported signature algorithms.
isEncrypted()
Check if a JWT's content is encrypted.
static getSupportedAlgorithms()
Return an array of supported signature algorithms.
getHeader($name, $defaultValue=null)
Get the value of the header with the specified name.
getClaim($name, $defaultValue=null)
Get the value of the claim with the specified name.
static sign($payload, $signatureMethod, $privateKey, $kid=null, $jku=null, $encryptionMethod=null, $publicKey=null)
Sign the JWT.
hasHeader($name)
Check whether a JWT has a header with the specified name.
getPayload()
Get the value of the payload.
hasClaim($name)
Check whether a JWT has a claim with the specified name.
verify($publicKey, $jku=null)
Verify the signature of the JWT.
Class to implement utility methods.
static jsonDecode($str, $associative=false)
Decode a JSON string.
Interface to represent an HWT client.