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. 0 means the cache never expires (not recommended).
$jwk_set = JWKFactory::createFromJKU('http://www.example.com/certs', false, $cacheItemPool, $ttl);
During tests for example, it is useful to retrieve keys using a non-encrypted connection (HTTP).
From the version 6.1 of this library, it is possible to allow URLs with the http://
scheme.
You just have to set the last argument as true
.
use Jose\Factory\JWKFactory;
$jwk_set = JWKFactory::createFromJKU('http://www.example.com/certs', false, null, 0, true);
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, HTTP 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
method.
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
);
The random keys created with that JWKSet are all of the same type. The configuration of those keys depends on their type and is similar to the configuration of a random key.
The main difference is that you do not have to define a kid
as it is automatically generated.
Additional paramters are accepted and are set for all key within the key set.
The following example will create oct
keys.
The key size is 256 bits ('size' => 256
) and that key will be used with the HS256
algorithm for signature/verification only.
use Jose\Factory\JWKFactory;
$jwk = JWKFactory::createStorableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'oct',
'size' => 256,
'alg' => 'HS256',
'use' => 'sig',
'foo' => 'bar',
],
3, // Number of keys in that key set
);
The following example will create RSA
keys.
The key size is 4096 bits and that key will be used with the RSA-OAEP
algorithm for encryption/decryption only.
use Jose\Factory\JWKFactory;
$jwk = JWKFactory::createStorableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'RSA',
'size' => 4096,
'alg' => 'RSA-OAEP',
'use' => 'enc',
],
3, // Number of keys in that key set
);
The following example will create EC
keys.
The key uses the P-521
curve and will be used with the ES512
algorithm for signature/verification only.
use Jose\Factory\JWKFactory;
$jwk = JWKFactory::createStorableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'EC',
'crv' => 'P-521',
'alg' => 'ES512',
'use' => 'sig',
],
3, // Number of keys in that key set
);
The following example will create OKP
keys.
The key uses the X25519
curve and will be used with the ECDH-ES
algorithm for encryption/decryption only.
use Jose\Factory\JWKFactory;
$jwk = 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
);
This configuration is absolutely useless as it is not relevant to use 3 "random" none
keys.
However this configuration is possible.
use Jose\Factory\JWKFactory;
$jwk = JWKFactory::createStorableKeySet(
'/path/to/the/storage/file.keyset', // The file which will contain the key set
[
'kty' => 'none',
],
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. This kind of key set is configured exactly like a random key set.
Those JWKSets implement the Jose\Object\RotatableInterface
and the method rotate
.
You can manipulate that key set as any other key sets, however you cannot add or remove keys.
We 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.