The JWKSet object represents a key set and is able to store multiple keys.
The class Jose\Object\JWKSet
implements the interface Jose\Object\JWKSetInterface
and provides the following methods:
getKey($index)
: get the key at index$index
getKeys()
: get all keysaddKey(JWKInterface $key)
: add a keyremoveKey($key)
: remove a key at index$index
Note that a JWKSet object
- is countable: you can call method
count()
, - is traversable: you can use a JWK as
foreach
argument - is serializable: You can call
json_encode($jwkset)
to display the key set as a string (e.g.{'keys':[{'kty':'oct', 'k':'abcdef...'}]}
). Such string is mainly used to share public keys through an URL. - can be used like an array
$jwkset[] = $jwk;
: Add a new key in the key set$jwkset[$index];
: Return the key at the index$index
.$index
must be an integer.unset($jwkset[$index]);
: Remove the key at the index$index
Example:
use Jose\Object\JWKSet;
$jwkset = new JWKSet();
$jwkset->addKey($key1); // or $jwkset[] = $key1;
print_r(json_encode($jwkset)); // {'keys':[{'kty':'oct', 'k':'abcdef...'}]}
Your key sets may be stored in a json encoded string or are available through an URL.
You can easily load and create key sets from several sources using the Jose\Factory\JWKFactory
factory provided with this library.
use Jose\Factory\JWKFactory;
$jwk_set = JWKFactory::createFromValues(['keys' => [
[
'kty' => 'EC',
'crv' => 'P-256',
'x' => 'weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ',
'y' => 'e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck',
'd' => 'VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw',
],
[
'kty' => 'EC',
'crv' => 'P-256',
'x' => 'gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0',
'y' => 'SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps',
'd' => '0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo',
],
]);
Please note that the above method will give the same result as the following one. The only difference is that the first method uses a static call on the factory instead of creating an object through a new instance. We recommend you to use the first method.
use Jose\Object\JWKSet;
$jwk_set = new JWKSet(['keys' => [
[
'kty' => 'EC',
'crv' => 'P-256',
'x' => 'weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ',
'y' => 'e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck',
'd' => 'VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw',
],
[
'kty' => 'EC',
'crv' => 'P-256',
'x' => 'gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0',
'y' => 'SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps',
'd' => '0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo',
],
]);
This method will try to load keys from an Url. The Url must contain a valid JWKSet.
The following example will try to load Google public keys:
use Jose\Factory\JWKFactory;
$jwk_set = JWKFactory::createFromJKU('https://www.googleapis.com/oauth2/v2/certs');
The URL to get the JWKSet is supposed to be secured as per the specification. However, you may need to retrieve your JWKSet through an unsecured connection (e.g. during tests).
Unsecured connections are:
- Connections with the
http
scheme - Connection to a server that provides self-signed certificates or invalid certificates.
The method createFromJKU
allows unsecured connection. Just set the second as true
:
use Jose\Factory\JWKFactory;
$jwk_set = JWKFactory::createFromJKU('http://www.example.com/certs', true);
To avoid calls to a server each time you need a certificate, the createFromJKU
supports PSR-6: Caching Interface compatible cache item pools.
use Jose\Factory\JWKFactory;
$cacheItemPool = YourValidCacheItemPool //An instance of a class that implements Psr\Cache\CacheItemPoolInterface
$ttl = 300; //Cache lifetime in seconds. Default is 86400 = 24 hrs.
$jwk_set = JWKFactory::createFromJKU('http://www.example.com/certs', false, $cacheItemPool, $ttl);
This method will try to load keys from an Url. The Url must contain a valid X509 certificate list.
The following example will try to load Google public keys:
use Jose\Factory\JWKFactory;
$jwk_set = JWKFactory::createFromX5U('https://www.googleapis.com/oauth2/v1/certs');
The method createFromX5U
supports the same arguments as the method createFromJKU
for unsecured connections or caching support.
You may need to create and store a key set with random keys.
This library provides an easy way to create such key set by using the createStorableKeySet
use Jose\Factory\JWKFactory;
$rotatable_key_set = JWKFactory::createStorableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'OKP',
'crv' => 'X25519',
'alg' => 'ECDH-ES',
'use' => 'enc',
],
3, // Number of keys in that key set
);
Some applications may require a key set with keys that are updated after a period of time. To continue to validate JWS or decrypt JWE, the old keys should be able for another period of time.
That is the purpose of the Rotatable Key Set.
You have to define which type of key you want to have (only one type per JWKSet allowed), how many keys in the key set and a period of time. Keys are automatically created and rotation is performed after the period of time.
You can manipulate that key set as any other key sets, however we recommend you to never add or remove keys. All changes will be erased we keys are rotated. We also recommend you to use the first key of that key set to perform your signature/encryption operations.
Except when the key set is created, all keys will be available at least during number of key * period of time
.
use Jose\Factory\JWKFactory;
$rotatable_key_set = JWKFactory::createRotatableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'OKP',
'crv' => 'X25519',
'alg' => 'ECDH-ES',
'use' => 'enc',
],
3, // Number of keys in that key set
3600 // This key set will rotate all keys after 3600 seconds (1 hour)
);
In some cases you may need to merge key sets and use it as a unique key set.
Then the JWKSets
class is made for you.
use Jose\Factory\JWKFactory;
$key_sets = JWKFactory::createKeySets([
$jwkset1,
$jwkset2,
$jwkset3,
...
]);
In some cases you may need to share public keys with third parties. This library provides a JWKSet that returns only public keys.
It is compatible with the any JWKSet, including JWKSets
or RotatableJWKSet
classes.
use Jose\Factory\JWKFactory;
$public_key_set = JWKFactory::createPublicKeySet($jwkset);
Let say you have two rotatable key sets: one for signature and the other one for encryption purpose. You want to share the public keys with third parties by providing a unique URL where all public keys can be retrieved.
Then you can merge your rotatable key sets and use that JWKSet to share public keys.
use Jose\Factory\JWKFactory;
$signing_keys = JWKFactory::createRotatableKeySet(
'/path/to/the/storage/signature.keyset',
[
'kty' => 'RSA',
'size' => 4096,
'alg' => 'RS512',
'use' => 'sig',
],
3,
3600
);
$encryption_keys = JWKFactory::createRotatableKeySet(
'/path/to/the/storage/encryption.keyset',
[
'kty' => 'OKP',
'crv' => 'X25519',
'alg' => 'ECDH-ES',
'use' => 'enc',
],
3,
3600
);
$jwkset = JWKFactory::createKeySets([
$signing_keys,
$encryption_keys,
]);
$public_key_set = JWKFactory::createPublicKeySet($jwkset);
Now you cqn use the first key of the $signing_keys
and $encryption_keys
for all your operations and share the $public_key_set
with third parties.
JWKSet object can contain several keys. To easily find a key according to constraint, a method selectKey
is available.
// Find a key used to encrypt/decrypt
$jwk_set->selectKey('enc');
// Find a key used to sign/verify
$jwk_set->selectKey('sig');
// Find a key used to sign/verify using the algorithm 'RS256'
$jwk_set->selectKey('sig', 'RS256');
// Find a key used to encrypt/decrypt with kid = '0123456789'
$jwk_set->selectKey('enc', null, ['kid'=>'0123456789']);
// Find a key used to sign/verify with sha256 thumbprint = '0123456789'
$jwk_set->selectKey('sig', null, ['x5t#256'=>'0123456789']);
We recommend you to always define the following key/value pairs for each key:
kid
: the ID of the keyuse
: the usage of the key (sig
for signature orenc
for encryption operations)alg
: the algorithm allowed for this key
The selection of the best key to use will be more efficient.