Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
To perform cryptographic operations (signature/verification and encryption/decryption), you will need keys. The keys can be grouped in key sets.
The JWK
and JWKSet
objects are part of the web-token/jwt-core
component:
A JWK object represents a key. It contains all parameters needed by the algorithm and also information parameters.
This framework is able to create private and public keys easily. It can also generate those keys from external resources.
Read this section to know how to create your keys.
A JWKSet object represents a key set. It can contain several keys.
We recommend you to avoid mixing public, private or shared keys in the same key set.
Please refer to this page to know how to create and use the key sets.
You can create a JWKSet object using three static methods:
JWKSet::createFromKeys(array $keys)
: creates a JWKSet using a list of JWK objects.
JWKSet::createFromJson(string $json)
: creates a JWKSet using a JSON object.
JWKSet::createFromKeyData(array $values)
: creates a JWKSet using a decoded JSON object.
Hereafter all methods available for a JWKSet object. The variable $jwkset
is a valid JWKSet object.
Please note a JWKSet object is an immutable object
We recommend you to avoid mixing public, private or shared keys in the same key set.
The algorithm management is part of the web-token/jwt-core
component:
For each cryptographic operation you will perform, you will need at least one algorithm.
The available algorithms depend on the cypher operation to be performed. Please refer to the Signed tokens or the Encrypted tokens to know more.
These algorithms are managed by an Algorithm Manager. In the following example, we will create an algorithm manager that will handle two algorithms: PS256
and ES512
It is not possible to set the same algorithm twice in the same algorithm manager.
Your application may need several algorithm managers for several use cases. Let say:
Your application issues signed events,
Your application issues authentication tokens for registered users or a resource server.
To avoid mixing algorithms in one algorithm manager or instantiate several times the algorithms for several algorithm managers, this framework provides an Algorithm Manager Factory.
This factory will create algorithm managers on demand. It also allows the same algorithm to be instantiated multiple times but with different configuration options.
Each algorithm is identified using an alias.
The first argument of the method add
is the alias for the algorithm. It must be unique. In general, this alias corresponds to the algorithm name.
As you can see in the example, we added the algorithm PBES2-HS512+A256KW
twice: with the default configuration and with custom arguments.
Now our algorithm manager factory is ready. We can create several algorithm managers by passing a list of aliases to the method create
:
This framework provides several components that will help you to use JWS (signed tokens) and JWE (encrypted tokens). It also provides other nice features to create and manage keys.
Before to start creating your first tokens, we have to create an algorithm manager and keys or key sets.
When your algorithm manager, your keys and your checkers are ready, you will be able to create or load your first tokens.
When you receive a JWT (JWS or JWE), it is important to check its headers before any other action. In case something went wrong, the token has to be rejected.
To use the header checker, install the corresponding component:
The header parameters are checked by a Header Checker Manager. This manager can contain several header checkers.
Please note that:
the header parameter crit
(critical) is always checked.
even if the JWS and JWE Loaders will check the alg
/enc
header parameters, it is interesting to check them through this manager.
To create a header checker manager, you will need to add header checkers and at least one token type. You will find token type classes for the JWS and JWE tokens in the web-token/jwt-signature
and web-token/jwt-encryption
components respectively.
In the following example, we want to check the alg
header parameter for the signed tokens (JWS) received by our application.
The usage of this class is pretty easy you just have to call the check
method. The first parameter is the JWT to check, the second one is the index of the signature/recipient.
In some cases, it could be interesting to reject tokens that do not contain some mandatory header parameters. A list of mandatory parameters can be set as third argument. If one of those parameters is missing an exception is thrown, even if that header parameter have not been checked.
In the following example, an exception will be thrown if the alg
, enc
or crit
parameters is missing.
The Header Checker Manager Factory will help you to create as many Header Checker Manager as you want to fit on your application requirements.
with the previous examples, we will only check the alg
(algorithm) header parameter. But your application may use other header parameters e.g. cty
, typ
...
The following header checkers are provided:
AlgorithmChecker
: checks the alg
header parameter.
AudienceChecker
: checks the aud
header parameter. This is a replicated claim as per the RFC7516 section 5.3
UnencodedPayloadChecker
: checks the b64
header parameter. See unencoded payload for more information.
If you need, you can create you own header checker. It must implement the interface Jose\Component\Checker\HeaderChecker
. In the following example, we will check that the protected header parameter custom
is an array with value foo
or bar
.
You can create a JWK object using two static methods:
JWK::create(array $values)
: creates a JWK using direct values.
JWK::createFromJson(string $json)
: creates a JWK using a JSON object.
Hereafter all methods available for a JWK object. The variable $jwk
is a valid JWK object.
Please note a JWK object is an immutable object
This framework is able to create private and public keys easily using the JWKFactory
. It is available in the web-token/jwt-key-mgmt
component.
4 types of keys are supported:
Symmetric Key:
oct
: octet string
Asymmetric Key:
RSA
: RSA key pair
EC
: Elliptic Curve key pair
OKP
: Octet key pair
Note: for the none
algorithm, the framework needs a key of type none
. This is a specific key type that must only be used with this algorithm.
The following example will show you how to create an oct
key.
Additional parameters will be set to limit the scope of this key (e.g. signature/verification only with the HS256
algorithm).
The following feature was introduced in version 1.1.
If you already have a shared secret, you can use it to create an oct
key:
The following example will show you how to create a RSA
key.
The key size must be of 384 bits at least.
The following example will show you how to create a EC
key.
The supported curves are:
P-256
P-384
P-521
(note that this is 521 and not 512)
The following example will show you how to create a OKP
key.
The supported curves are:
Ed25519
for signature/verification only
X25519
for encryption/decryption only
The none
key type is a special type used only for the none
algorithm.
In case you already have key values, you can create a key by passing those values as an argument:
You can convert a PKCS#1 or PKCS#8 key file into a JWK. The following method supports PEM and DER formats. Encrypted keys are also supported.
You can convert a PKCS#12 Certificate into a JWK. Encrypted certificates are also supported.
You can convert a X.509 Certificate into a JWK.
Please note that X.509 certificates only contains public keys.
This document is available online at https://web-token.spomky-labs.com.
This framework provides an implementation of:
This framework is not just a library, it also contains a Symfony bundle for easy integration into your application. It also provides a standalone console command that will help you to manage your keys and key sets.
JWS or JWE objects support every input that can be encoded into JSON:
string
, array
, integer
, float
...
Objects that implement the \JsonSerializable
interface such as JWK
or JWKSet
The detached payload is supported.
Compact JSON Serialization Syntax for JWS and JWE
Flattened JSON Serialization Syntax for JWS and JWE
General JSON Serialization Syntax for JWS and JWE
JWK objects support JSON Web Key Thumbprint (RFC 7638).
Note: we use a none
key type for the none
algorithm only.
JWKSet is fully supported.
This framework needs at least:
GMP extension.
MBString extension.
Depending on the algorithms you using, other PHP extensions may be required (e.g. OpenSSL).
Please also consider the following optional requirements:
If you intent to use EdDSA
or ECDH-ES
algorithm with Ed25519
/X25519
curves on PHP 7.1, please install this third party extension
It has been successfully tested using PHP 7.1
, PHP 7.2
and nightly
with all algorithms.
Tests vectors from the RFC 7520 are fully implemented and all tests pass. Other test vector sources may be used (e.g. new algorithm specifications).
We also track bugs and code quality using Scrutinizer-CI and Sensio Insight.
Coding Standards are verified by StyleCI.
Code coverage is analyzed by Coveralls.io.
To avoid security issues on your application, please follow these Security Recommendations carefully.
Please read the performance page to know how to test the algorithms of the framework.
You can also see the last benchmarks made with our development environment.
Requests for new features, bug fixed and all other ideas to make this framework useful are welcome. If you feel comfortable writing code, you could try to fix opened issues where help is wanted or those that are easy to fix.
Do not forget to follow these best practices.
If you think you have found a security issue, DO NOT open an issue. You MUST submit your issue here.
This project is release under MIT licence.
This framework comes with several signature algorithms. These algorithms are in the following namespace: Jose\Component\Signature\Algorithm
.
From v1.2, the algorithms have their own sub-packages. To avoid BC breaks, these packages are automatically installed for all v1.x of the framework. Starting at v2.0, you will have to explicitly install the algorithm packages you need.
HMAC with SHA-2 Functions. Package web-token/jwt-signature-algorithm-hmac
HS256
HS384
HS512
Elliptic Curve Digital Signature Algorithm (ECDSA). Package web-token/jwt-signature-algorithm-ecdsa
ES256
ES384
ES512
RSASSA-PKCS1 v1_5. Package web-token/jwt-signature-algorithm-rsa
RS256
RS384
RS512
RSASSA-PSS. Package web-token/jwt-signature-algorithm-rsa
PS256
PS384
PS512
Edwards-curve Digital Signature Algorithm (EdDSA) Package web-token/jwt-signature-algorithm-eddsa
EdDSA
(only with the Ed25519
curve)
Unsecured algorithm Package web-token/jwt-signature-algorithm-none
none
The following signature algorithms are experimental and must not be used in production unless you know what you are doing. They are proposed for testing purpose only.
They are all part of the package web-token/jwt-signature-algorithm-experimental
RS1
: RSASSA-PKCS1 v1_5 with SHA-1 hashing function.
HS1
: HMAC with SHA-1 hashing function.
Example:
To use the encrypted tokens (JWE), you have to install the .
This component provides lot of encryption algorithms and classes to load and create encrypted tokens.
Please refer to to know what algorithms are available.
Then, you will find an and another incoming tokens.
Now that you have an algorithm manager and a key, it is time to create your first signed token.
The computation is done by the JWSBuilder
object. This object requires the algorithm manager and a JSON converter. In the following example, we will use the standard converter provided by the framework.
Now let's create our first JWS object.
Great! If everything is fine you will get a JWS object with one signature. We want to send it to the audience. Before that, it must be serialized.
We will use the compact serialization mode. This is the most common mode as it is URL safe and very compact. Perfect for a use in a web context!
All good! The variable $token
now contains a string that should be something like this:
Other serialization modes exist. We will see them in the Advanced Topics section.
Signed tokens are loaded by a serializer or the serializer manager and verified by the JWSVerifier
object. This JWSVerifier object just requires an algorithm manager.
In the following example, we will try to load a signed token. We will only use the HS256
algorithm.
Now we can deserialize the input we receive and check the signature using our key. We will continue with the data we got in the JWS creation section.
Note: we do not check header parameters here, but it is very important to do it. This step is described in the Header Checker section.
The method verifyWithKey
returns a boolean. If true, then your token signature is valid. You can then check the claims (if any) using the claim checker manager.
To avoid duplication of code lines, you can create a JWSLoader
object. This object contains a serializer, a verifier and an optional header checker (highly recommended).
In the following example, the JWSLoader
object will try to unserialize the token $token
, check the header parameters and verify the signature with the key $jwk
. The variable $payload
corresponds to the detached payload (null
by default).
If the verification succeeded, the variable $signature
will be set with the signature index and should be in case of multiple signatures. The method returns the JWS object.
In case you use a key set, you can use the method loadAndVerifyWithKeySet
.
This feature was introduced in version 1.1.
The JWSLoaderFactory
object is able to create JWSLoader
objects on demand. It requires the following factories:
JWSSerializerManagerFactory
JWSVerifierFactory
HeaderCheckerManagerFactory
(optional)
JSON Web Tokens can be used to transport any kind of data. They are mainly used to transport claims. When you receive a tokens that contains claims, it is important to check the values of these claims.
The Claim Checker Manager is responsible of this task. To use it, install the corresponding component:
In the following example, we will create a manager able to check the aud
(Audience), iat
(Issued At), nbf
(Not Before) and exp
(Expiration) claims.
When instantiated, call the method check
to check the claims of a JWT object. This method only accept an array. You have to retrieve this array by converting the JWT payload.
In some cases, it could be interesting to reject tokens that do not contain some mandatory claims. A list of mandatory claims can be set as second argument. If one of those claims is missing an exception is thrown, even if the claim have not been checked.
In the following example, an exception will be thrown if the iss
, sub
or aud
claim is missing.
Your application may use other claims that you will have to check therefore custom claim checkers have to be created.
In this example, we will create a class that will check the claim foo
. The claim accept only a string with the value bar
or bat
. All claim checker have to implement the interface Jose\Component\Checker\ClaimChecker
;
All done! Now you can instantiate your class and add it to your Claim Checker Manager.
Have a look at the IssuedAtChecker
or the NotBeforeChecker
classes. These checkers can be used for claim and header checks.
Your application may use JSON Web Tokens in different contexts and thus the meaning of a claim may be different. You will need several Claim Checker Managers with dedicated claim checkers.
This framework provides an Claim Checker Manager Factory. This factory is able to accept as many claim checkers as you need. Each claim checker you add to this factory is associated to an alias. You will then be able to create a claim checker manager using those aliases.
To use the signed tokens (JWS), you have to install the .
This component provides lot of signature algorithms and classes to load and create signed tokens.
Please refer to to know what algorithms are available.
Then, you will find an and another incoming tokens.
,
These algorithms have to be used with the . They do not need any arguments.
The allows to replicate some claims in the header. This behaviour is very useful with encrypted tokens as it helps to reject invalid tokens without decryption of the payload.
The Claim Checker Manager cannot check those replicated claims, you have to create a . However, to avoid duplicated classes, your claim checker can implement the Jose\Component\Checker\HeaderChecker
interface.
Compression Method
Supported
Comment
Deflate (DEF
)
YES
GZip (GZ
)
YES
This compression method is not described in the specification
ZLib (ZLIB
)
YES
This compression method is not described in the specification
Key Type
Supported
Comment
oct
YES
Symmetric keys
RSA
YES
RSA based asymmetric keys
EC
YES
Elliptic Curves based asymmetric keys
OKP
YES
Octet Key Pair based asymmetric keys
Signature Algorithm
Supported
Comment
HS256, HS384 and HS512
YES
ES256, ES384 and ES512
YES
RS256, RS384 and RS512
YES
PS256, PS384 and PS512
YES
none
YES
Please note that this is not a secured algorithm. USE IT WITH CAUTION!
EdDSA with Ed25519 curve
YES
EdDSA with Ed448 curve
NO
No extension or built-in implementation available
HS1
YES
From v1.2. Experimental. Not recommended ; for testing purpose or compatibility with old systems only.
RS1
YES
From v1.2. Experimental. Not recommended ; for testing purpose or compatibility with old systems only.
HS256/64
YES
From v1.2. Experimental. Not recommended ; for testing purpose or compatibility with old systems only.
Key Encryption Algorithm
Supported
Comment
dir
YES
RSA1_5, RSA-OAEP and RSA-OAEP-256
YES
The algorithms RSA1_5 and RSA-OAEP are now deprecated. Please use with caution.
ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW and ECDH-ES+A256KW
YES
A128KW, A192KW and A256KW
YES
PBES2-HS256+A128KW, PBES2-HS384+A192KW and PBES2-HS512+A256KW
YES
A128GCMKW, A192GCMKW and A256GCMKW
YES
ECDH-ES with X25519 curve
YES
ECDH-ES with X448 curve
NO
No extension or built-in implementation available
RSA-OEAP-384 and RSA-OAEP-512
YES
From v1.2. Experimental. For testing purpose only.
ChaCha20-Poly1305
YES
From v1.2. Experimental. For testing purpose only.
Content Encryption Algorithm
Supported
Comment
A128CBC+HS256, A192CBC+HS384 and A256CBC+HS512
YES
A128GCM, A192GCM and A256GCM
YES
A128CTR, A192CTR and A256CTR
YES
From v1.2. Not recommended. For testing purpose only.
This framework comes with several encryption algorithms. These algorithms are in the following namespaces:
Jose\Component\Encryption\Algorithm\KeyEncryption
: key encryption algorithms
Jose\Component\Encryption\Algorithm\ContentEncryption
: content encryption algorithms
From v1.2, the algorithms have their own sub-packages. To avoid BC breaks, these packages are automatically installed for all v1.x of the framework. Starting at v2.0, you will have to explicitly install the algorithm packages you need.
Key Encryption
Package web-token/jwt-encryption-algorithm-aeskw
A128KW
A192KW
A256KW
Package web-token/jwt-encryption-algorithm-aesgcmkw
A128GCMKW
A192GCMKW
A256GCMKW
Package web-token/jwt-encryption-algorithm-dir
dir
(class Dir
)
Package web-token/jwt-encryption-algorithm-ecdh-es
ECDH-ES
(class ECDHES
) READ THE NOTE BELOW
ECDH-ES+A128KW
(class ECDHESA128KW
) READ THE NOTE BELOW
ECDH-ES+A192KW
(class ECDHESA192KW
) READ THE NOTE BELOW
ECDH-ES+A256KW
(class ECDHESA256KW
) READ THE NOTE BELOW
Package web-token/jwt-encryption-algorithm-pbes2
PBES2-HS256+A128KW
(class PBES2HS256A128KW
)
PBES2-HS384+A192KW
(class PBES2HS384A192KW
)
PBES2-HS512+A259KW
(class PBES2HS512A1256KW
)
Package web-token/jwt-encryption-algorithm-rsa
RSA1_5
(class RSA15
) READ THE NOTE BELOW
RSA-OAEP
(class RSAOAEP
)
RSA-OAEP-256
(class RSAOAEP256
)
Content Encryption
Package web-token/jwt-encryption-algorithm-aesgcm
A128GCM
A192GCM
A256GCM
Package web-token/jwt-encryption-algorithm-aescbc
A128CBC-HS256
(class A128CBCHS256
)
A192CBC-HS384
(class A192CBCHS384
)
A256CBC-HS512
(class A256CBCHS512
)
IMPORTANT NOTE:
The algorithm RSA1_5
is deprecated due to known security vulnerability.
The algorithms ECDH-ES*
are not recommended unless used with the OKP
key type.
The following signature algorithms are experimental and must not be used in production unless you know what you are doing. They are proposed for testing purpose only.
They are all part of the package web-token/jwt-encryption-algorithm-experimental
Key Encryption
A128CTR
, A192CTR
and A256CTR
: AES CTR based encryption.
Chacha20+Poly1305
: Please note that this algorithm requires OpenSSL 1.1
RSA-OAEP-384
and RSA-OAEP-512
: Same algorithm as RSA-OAEP-256 but with SHA-384 and SHA-512 hashing functions.
Content Encryption
AxxxCCM-16-128
, AxxxCCM-16-64
, AxxxCCM-64-128
, AxxxCCM-64-64
: AES-CCM based aalgorithms. xxx can be 128 or 256.
These algorithms have to be used with the Algorithm Manager. They do not need any arguments.
Example:
By default, PBES2*
algorithms use the following parameter values:
Salt size: 64 bytes (512 bits)
Count: 4096
You may need to use other values. This can be done during the instantiation of the algorithm:
Example with 16 bytes (128 bits) salt and 1024 counts:
The JWK and JWKSet objects are provided by the web-token/jwt-core
component. We recommend you to load these objects through environment variables.
With Symfony 3.4 or 4.0+, an environment variables processor is provided:
With the previous configuration, the environment variables MY_PRIVATE_KEY
and MY_PUBLIC_KEYSET
will be processed by Symfony and the container will contain the my_private_key
and my_public_keyset
with JWK and JWKSet objects respectively.
But it may not be sufficient for your project. You may need to load keys or key sets from other sources (e.g. key file) You may also want to use your keys as a container services you inject to other services.
This behaviour is possible by installing the web-token/jwt-key-mgmt
component. To install it, just execute the following command line:
Encrypted tokens are loaded by a serializer or the serializer manager and decrypted by the JWEDecrypter
object. This JWEDecrypter object requires several services for the process:
an algorithm manager with key encryption algorithms
an algorithm manager with content encryption algorithms
a compression method manager. No compression method is needed if you do not intent to compress the payload.
In the following example, we will use the same assumptions as the ones used during the JWE Creation process.
Now we can try to deserialize and decrypt the input we receive. We will continue with the result we got during the JWE creation section.
Note: we do not check header parameters here, but it is very important to do it. This step is described in the Header Checker section.
OK so if not exception is thrown, then your token is loaded and the payload correctly decrypted.
To avoid duplication of code lines, you can create a JWELoader
object. This object contains a serializer, a decrypter and an optional header checker (highly recommended).
In the following example, the JWELoader
object will try to unserialize the token $token
, check the header parameters and decrypt with the key $key
.
If the decryption succeeded, the variable $recipient
will be set with the recipient index and should be in case of multiple recipients. The method returns the JWE object.
In case you use a key set, you can use the method loadAndDecryptWithKeySet
.
This feature was introduced in version 1.1.
The JWELoaderFactory
object is able to create JWELoader
objects on demand. It requires the following factories:
JWESerializerManagerFactory
JWEDecrypterFactory
HeaderCheckerManagerFactory
(optional)
The Symfony Bundle provides an Algorithm Manager Factory service. The available algorithms depends on the components installed on your application.
This factory handles all algorithms services tagged with jose.algorithm
.
Example:
Your algorithm will be available through the algorithm manager factory service and the alias FOO
.
When installed, the PBES2-*
algorithms available throught the algorithm manager factory. They have the default configuration i.e. salt size = 62 bits and count = 4096. If these values does not fit on your needs, you can create a new algorithm service with your own values:
You can now use your custom alias:
This framework provides a Symfony bundle that will help you to use the components within your Symfony application. The bundle is available
when you just install the bundle (composer require web-token/jwt-bundle
)
when you install the whole framework (composer require web-token/jwt-framework
)
If you just install the bundle on an application with Symfony Flex support, then there is nothing to do. Otherwise, you have to register the bundle:
The bundle capabilities will depend on the components installed in your application. The core component is always available.
The Symfony Bundle provides Header and Claim Checker Manager Factory services. These services are available when the web-token/jwt-checker
component is installed:
You can create Header and Claim Checker Managers using the bundle configuration.
With the previous configuration, the bundle will create public Header and Claim Checker Managers named jose.header_checker.checker1
and jose.claim_checker.checker1
with selected checkers.
Some claim or header checkers are provided by this framework, but it is important to create custom checkers that fit on your application requirements.
In the following example, we will assume that the class exist and implement either Jose\Component\Checker\HeaderChecker
or Jose\Component\Checker\ClaimChecker
.
These checkers will be loaded by the factories and you will be able to create a header or a claim checker manager using the aliases foo
or bar
.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the header and claim checker managers.
When the component is installed, you will be able to define your keys in your application configuration and load your keys from several sources or formats. All these methods have the following option:
is_public
: set the service public or private.
The key configuration will look like as follow:
The key will be available as a container service with the ID jose.key.key_name
where key_name
is the unique name of your key. Each key service will be an instance of the Jose\Component\Core\JWK
class.
As any other configuration values, you can use environment variables.
This feature was introduced in version 1.1.
This method will directly get a shared secret.
This method will directly load a JWK object.
This method will load a X509 Certificate file.
This method will load a key from a X509 Certificate.
This method will load a key from a PKCS#1 or PKCS#8 key file.
This method will retrieve a key from a JWKSet service.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
To use the signed tokens (JWS), you have to install the .
When this component is installed, signature algorithms are automatically handles by the Algorithm Manager Factory.
,
,
.
A JWSSerializerManagerFactory
is available as a service in your application container:
With this factory, you will be able to create the JWSSerializerManager you need:
You can now use the JWSSerializerManager as explained in the JWS Creation/Loading section.
Available JWS serialization modes are:
jws_compact
jws_json_general
jws_json_flattened
There is also another way to create a JWSSerializerManager object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWS Serializer Manager service named jose.jws_serializer.serializer1
with selected serialization modes.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
A JWSBuilderFactory
is available as a service in your application container:
With this factory, you will be able to create the JWSBuilder you need:
You can now use the JWSBuilder as explained in the JWS Creation section.
There is also another way to create a JWSBuilder object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWS Builder service named jose.jws_builder.builder1
with selected signature algorithms.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
All these methods have the following common option:
is_public
: set the service public or private.
The key set configuration will look like as follow:
The key set will be available as a container service with the ID jose.key_set.keyset_name
where keyset_name
is the unique name of your key set. Each key set service will be an instance of the Jose\Component\Core\JWKSet
class.
As any other configuration values, you can use environment variables.
This method will directly get a JWKSet object.
When done, you have to create a client and enable the JKU Factory service by indicating the request factory service to use:
Important recommendations:
It is highly recommended to use a cache plugin for your HTTP client and thus avoid unnecessary calls to the key set endpoint.
The connection must be secured and certificate verification should not be disabled.
The following example will allow you tu load a key set from a distant URI. The key set must be a JWKSet object.
The following example will allow you tu load a key set from a distant URI. The key set must be a list of X509 certificates.
It can be interesting to share your key sets through an Url. This can easily achieved by adding a dedicated controller. This controller is automatically created by the bundle.
You must add the following configuration to your routing file.
Then you can share your key set.
Now went you go to the URL http://128.0.0.1:8000/certs
, you will get your key set.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
You can load key sets shared by a distant service (e.g. Google, Microsoft, Okta...). You must install and enable the .
To use the encrypted tokens (JWE), you have to install the web-token/jwt-encryption
component.
When this component is installed, encryption algorithms are automatically handles by the Algorithm Manager Factory.
A JWSVerifierFactory
is available as a service in your application container:
With this factory, you will be able to create the JWSVerifier you need:
You can now use the JWSVerifier as explained in the JWS Creation section.
Reminder: it is important to check the token headers. See the checker section of this documentation.
There is also another way to create a JWSVerifier object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWS Verifier service named jose.jws_verifier.verifier1
with selected signature algorithms.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
This feature was introduced in version 1.1.
The JWSLoaderFactory
is available as a public service. You can retrieve it using the container or inject it into your services. It will help you to create JWSLoader
objects on demand.
You can also create JWSLoader
objects as services using the configuration of the bundle.
Or using the ConfigurationHelper
.
A JWEDecrypterFactory
is available as a service in your application container:
With this factory, you will be able to create the JWEDecrypter you need:
You can now use the JWEDecrypter as explained in the JWE Creation section.
Reminder: it is important to check the token headers. See the checker section of this documentation.
There is also another way to create a JWEDecrypter object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWE Decrypter service named jose.jwe_decrypter.decrypter1
with selected encryption algorithms.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
This feature was introduced in version 1.1.
The JWELoaderFactory
is available as a public service. You can retrieve it using the container or inject it into your services. It will help you to create JWELoader
objects on demand.
You can also create JWELoader
objects as services using the configuration of the bundle.
Or using the ConfigurationHelper
.
A JWEBuilderFactory
is available as a service in your application container:
With this factory, you will be able to create the JWEBuilder you need:
Available compression methods are:
DEF
: deflate (recommended)
GZ
: gzip
ZLIB
: zlib
You can now use the JWEBuilder as explained in the JWE Creation section.
There is also another way to create a JWEBuilder object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWE Builder service named jose.jwe_builder.builder1
with selected encryption algorithms.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
A JWESerializerManagerFactory
is available as a service in your application container:
With this factory, you will be able to create the JWESerializerManager you need:
You can now use the JWESerializerManager as explained in the JWE Creation/Loading section.
Available JWE serialization modes are:
jwe_compact
jwe_json_general
jwe_json_flattened
There is also another way to create a JWESerializerManager object: using the bundle configuration.
With the previous configuration, the bundle will create a public JWE Serializer Manager service named jose.jwe_serializer.serializer1
with selected serialization modes.
This feature was introduced in version 1.1.
You can add custom tags and attributes to the services you create.
When you want to create keys/key sets, JWS loader/verifier... services, you have to create a dedicated jose
section in your configuration. It may confuse your users to configure your bundle and the Jose Framework bundle. Sometimes, you may also want to be sure that the configuration is correctly defined. Lastly, the configuration size increases with numerous details, options or service IDs and it becomes difficult to read or modify.
Hopefully, the Symfony bundle provide a configuration helper: Jose\Bundle\JoseFramework\Helper\ConfigurationHelper
. This helper will configure the jose
section for you. This helper has to be called in your bundle extension during the prepend
step (your extension has to implement Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface
).
Let say you want to create a JWK as a service:
For the key configuration, the arguments are:
The container
The name of the service (acme_my_key
)
The key type (jwk
)
An array with the expected values
An array with the custom tags (optional)
Now a key service named jose.key.acme_my_key
will be created. This service is public so you will be able to get it from your container or inject it to your services.
This is exactly the same configuration as the following one:
Please note that the tags have been introduced in version 1.1.
Other methods are:
For the jws
section:
public static function addJWSBuilder(ContainerBuilder $container, string $name, array $signatureAlgorithms, bool $is_public = true, array $tags = [])
public static function addJWSVerifier(ContainerBuilder $container, string $name, array $signatureAlgorithms, bool $is_public = true, array $tags = [])
public static function addJWSSerializer(ContainerBuilder $container, string $name, array $serializers, bool $is_public = true, array $tags = [])
For the jwe
section:
public static function addJWEBuilder(ContainerBuilder $container, string $name, array $keyEncryptionAlgorithm, array $contentEncryptionAlgorithms, array $compressionMethods = ['DEF'], bool $is_public = true, array $tags = [])
public static function addJWEDecrypter(ContainerBuilder $container, string $name, array $keyEncryptionAlgorithm, array $contentEncryptionAlgorithms, array $compressionMethods = ['DEF'], bool $is_public = true, array $tags = [])
public static function addJWESerializer(ContainerBuilder $container, string $name, array $serializers, bool $is_public = true, array $tags = [])
For the checker
section:
public static function addClaimChecker(ContainerBuilder $container, string $name, array $claimCheckers, bool $is_public = true, array $tags = [])
public static function addHeaderChecker(ContainerBuilder $container, string $name, array $headerCheckers, bool $is_public = true, array $tags = [])
For the keys
section:
public static function addKey(ContainerBuilder $container, string $name, string $type, array $parameters, array $tags = [])
For the key_sets
section:
public static function addKeyset(ContainerBuilder $container, string $name, string $type, array $parameters, array $tags = [])
For the jwk_uris
section:
public static function addKeyUri(ContainerBuilder $container, string $name, array $parameters, array $tags = [])
Have a look at the spomky-labs/lexik-jose-bridge
extension to see how we configure the Jose Bundle without dedicated configuration
Signed or Encrypted Tokens are not just the next trendy/popular way to authenticate users. They provide great features but when used incorrectly they can expose your application to major security issues.
Please read the following recommendations carefully.
If all parties are able to protect their keys (e.g. private applications), symmetric algorithms are a good choice as they are faster in general. If you use public clients, you should prefer asymmetric algorithms.
This framework provides dozen of signature and encryption algorithms, but you do not need all of them. Most applications only support 1 or 2 algorithms.
You should only use necessary algorithms. For example, HS384 algorithm may be avoided if you already have HS256 and HS512.
Some algorithms are not recommended as there are known security issues:
none
: this algorithm is not a real algorithm. It should only be used when other security means exist. An encrypted connection is certainly not enough!
RSA1_5
: there are known attacks using this algorithm. If you can avoid its use, then do it.
A small key size is as secured as a password like 123456789
. You should use at least 256 bits symmetric keys and at lease 2048 bits RSA keys.
In any case, you MUST use a true random number generator.
It is highly recommended to set the following parameters to yours key:
kid
: A unique key ID,
use
: indicates the usage of the key. Either sig
(signature/verification) or enc
(encryption/decryption).
alg
: the algorithm allowed to be used with this key.
A key is fine but may be cracked e.g. by bruteforce. Changing you keys after several days or weeks is encouraged.
Broadly speaking, you should set your header parameter in the protected header. The use of the unprotected header should be limited to specific use cases.
When using encrypted tokens, the claims iss
and aud
should be duplicated into the header. This will avoid unwanted decryption when tokens are sent to a wrong audience.
There is no size constraint for the payload, but when tokens are used in a web context, it should be as small as possible. When used, claims should be limited to the minimum.
Does your application really need to get all the information about a user? For each context, you should choose carefully the claims you want to use.
A unique token ID should be set to all tokens you create. The associated claim is jti
.
This claim is highly recommended as it can prevent replay attacks.
The JWT specification introduces several claims to limit the period of validity of the tokens:
exp
: expiration time,
iat
: issuance time,
nbf
: validity point in time.
These claims are not mandatory, but it is recommended to define a period of time for the token validity. When used, the expiration time should be in adaquation with the context of your application. A security token with 2 weeks lifetime is something you should avoid.
The claims iss
(issuer) and aud
(audience) should always be set. When duplicated in the header, their values MUST be identical.
Unless you use encrypted tokens, you should use a secured connection when transmitting tokens between parties. A secured communication is not only needed when transmitting tokens, but also when you exchange keys and key sets with other applications.
When you receive a token, the following steps should be followed in this order. If one failed, you you reject the whole token.
Unserialize the token
For each signature/recipient (may be possible when using the Json General Serialization Mode):
Check the complete header (protected and unprotected)
Verify the signature (JWS) or decrypt the token (JWE)
Check the claims in the payload (if any)
You should only use the serialization mode(s) you need. If you intent to use yur tokens in a web context, then use only the Compact Serialization. If an error occurred during this process, you should consider the token as invalid.
Header parameters have to be checked. You should at least check the alg
(algorithm) and enc
(only for JWE) parameters. The crit
(critical) header parameter is always checked.
Please note that unknown header parameters are ignored. If your token is verified, those parameters should not be used.
When used, unprotected header parameters should be handled with care.
Let the component do its job. The most important step for developers is to ensure that the right key/ket set is used.
This step is only required if the payload contains claims. When present, you should always check the exp
, iat
, nbf
, iss
and aud
claims. Application specific claims should also always checked.
The whole token should be rejected in case of failure. Unknown claims should be ignored.
You should subscribe to security forums of similar websites and have a continuous technological watch. The tokens may be compromised because of malicious attacks on the algorithms, keys or other components related to the JWT (directly or indirectly).
The project comes with console commands. They are available:
In the following example, we will call commands using ./jose.phar
. If you need more information about a command, call the command with the option --help
.
This command will convert a private key into a public key. It has no effect on shared keys (e.g. oct
keys).
The following command will analyze the key passed as argument and find issues.
This command will convert a RSA or EC key into PKCS#1 key.
The key generator commands will generate a private or shared key. The following options are available:
-o
or --out
: save the output into a file: --out private.key
.
-u
or --use
: indicates the usage of the key (sig
or enc
): --use enc
. This option is highly recommended.
-a
or --alg
: indicates the algorithm to be used with the key: --alg RSA-OAEP-256
. This option is highly recommended.
Elliptic Curve Key
This command will generate an Elliptic Curve key (EC). The supported curves are P-256
, P-384
and P-521
.
RSA Key
This command will generate a RSA key. The key size must be at least 384 bits. Recommended size is 2048 bits or more.
Octet Key
This command will generate a octet key (oct). Recommended size is 128 bits or more.
Octet Key Pair Key
This command will generate a octet key pair key (OKP). Supported curves are X25519
(for encryption only) and Ed25519
(signature only).
None Key
This command will generate a none key. This key type is only used by the none
algorithm. Key parameters alg
and use
are automatically set.
From An Existing Secret
This feature was introduced in version 1.1.
If you already have a secret, you can use it to create an octet key (oct
).
In case your secret is binary string, you will have to encode it first (Base64) and indicate it is encoded.
The key loader commands will loader keys from various sources. The following options are available:
-o
or --out
: save the output into a file: --out private.key
.
-u
or --use
: indicates the usage of the key (sig
or enc
): --use enc
. This option is highly recommended.
-a
or --alg
: indicates the algorithm to be used with the key: --alg RSA-OAEP-256
. This option is highly recommended.
Convert From PEM/DER Keys
This command can load and convert a DER/PEM key file into a JWK. It supports encrypted keys as well as PKCS#1 and PKCS#8 encodings or public/private keys.
Convert From PKCS#12 Keys
This command can load and convert a PKCS#12 key file into a JWK. It supports encrypted keys.
Convert From A X.509 Certificate
This command can load and convert a X.509 key file into a JWK.
This command optimizes a RSA key by calculating additional primes (CRT). The following option is available:
-o
or --out
: save the output into a file: --out private.key
.
RSA keys generated by this framework are already optimized. This command may be needed when you import RSA keys from external sources. The optimization is not mandatory but highly recommended. cryptographic operations are up to 10 times faster.
-o
or --out
: save the output into a file: --out private.key
.
This command has the same affect as key:convert:public
except that it will convert all keys in the keyset. It has no effect on shared keys (e.g. oct
keys).
This command has the same behaviour as key:analyze
except that it will analize all keys in the keyset.
The key set generator commands will generate key sets with random keys of the same type.
These commands have the same options as the key generator commands. The only difference is that you have to indicate the number of keys you want in the key set.
Examples:
The result of these commands is a JWKSet object.
keyset:add:key
: Add a key into a key set.
keyset:merge
: Merge several key sets into one.
keyset:rotate
: Rotate a key set.
keyset:load:jku
: Loads a key set from an url.
keyset:load:x5u
: Loads a key set from an url.
To install the application, you just have to download it and download the associated public key (the application is digitally signed):
If everything is fine, you should have two files:
jose.phar
jose.phar.pubkey
You can move these files wherever you want (e.g. /usr/local/bin
).
To use it, just execute the following line:
The application can be updated easily:
If a new version exists, it will be downloaded automatically. If there is something wrong with the new version, you can reinstall the previous revision:
To enable the commands on a Symfony application, you have to install and add the associated bundle into your kernel:
If you use Symfony Flex, you have nothing to do. Otherwise you have to enable to bundle.
Then execute your Symfony Console command to use the command provided by this component:
The is a good start.
This command will calculate the key thumbprint as per the . The following options are available:
--hash
: the hashing method. Default is sha256
. Supported methods are the one listed by .
As per the RFC7519,the payload of a JWS may be detached. This framework supports this feature.
There is not much difference between the creation of a JWS with or without detached payload. The following example comes from the JWS Creation page. There is only one argument that will change during the call of withPayload
.
And voilà! When you will serialize this token, the payload will not be present.
The loading of a signed token with a detached payload is as easy as when the payload is attached. The only difference is that you have to pass the payload to the JWS Verifier when you want to check the signature.
When you need to sign the same payload for several audiences, you may want to do it at once. The JWS Builder supports multiple signatures.
With the example below, we will create three signatures using three different algorithms (and signature keys):
The variable $jws
will be a valid JWS object with all computed signatures. Next step is the serialization of these signatures.
You may want to set data in a token header that are not important for your application (e.g. general information). The integrity protection of the data is therefore not needed at all.
The RFC7515 introduces an unprotected header. This header is supported by this framework.
With the example below, we will create a signed token with some unprotected header parameters:
The variable $jws
will be a valid JWS object with one signature and both headers.
Note: when an unprotected header is set, the Compact Serialization mode is not available.
The RFC7515 (JWS) and RFC7516 (JWE) introduce several serialization modes.
Compact
JSON Flattened
JSON General
The Compact mode is most know and commonly used as it is compact and URL safe i.e. it is designed for web context. JSON Flattened and General are not URL safe, but provides features that may fit on your application context.
To use the JWS serializers, you have to install the jwt-signature
component.
This serialization mode is probably the one you know the most. It it a string composed of three parts encoded in Base64 Url Safe and separated by a dot (.
).
The serializer class is Jose\Component\Signature\Serializer\CompactSerializer
. The associated name is jws_compact
.
Example:
There are some limitations when you use this serialization mode:
Unprotected header not supported.
Unencoded payload must contain characters within the following range of ASCII characters: 0x20-0x2d and 0x2f-0x7e
This serialization mode is useful when you need to use the unprotected header. It it a simple JSON object.
The serializer class is Jose\Component\Signature\Serializer\JSONFlattenedSerializer
. The associated name is jws_json_flattened
.
Example:
This serialization mode is similar to the JWS JSON Flattened, but may contain more than one signature. It it a JSON object.
The serializer class is Jose\Component\Signature\Serializer\JSONGeneralSerializer
. The associated name is jws_json_general
.
Example:
The serializer manager can be helpful when your application deals more than one serialization mode.
To use the JWE serializers, you have to install the jwt-encryption
component.
This serialization mode is probably the one you know the most. It it a string composed of five parts encoded in Base64 Url Safe and separated by a dot (.
).
The serializer class is Jose\Component\Encryption\Serializer\CompactSerializer
. The associated name is jwe_compact
.
Example:
There are some limitations when you use this serialization mode:
No Additional Authentication Data can be used.
No shared unprotected header or per-recipient header can be used.
This serialization mode is useful when you need to use the unprotected header. It it a simple JSON object.
The serializer class is Jose\Component\Encryption\Serializer\JSONFlattenedSerializer
. The associated name is jwe_json_flattened
.
Example:
This serialization mode is similar to the JWE JSON Flattened, but may contain more than one recipient. It it a JSON object.
The serializer class is Jose\Component\Encryption\Serializer\JSONGeneralSerializer
. The associated name is jwe_json_general
.
Example:
The serializer manager can be helpful when your application deals more than one serialization mode.
JWT can be signed or encrypted and both. A nested token is a signed token enclosed in an encrypted one. This order is very important: signed then encrypted.
The NestedTokenLoader
and NestedTokenBuilder
classes will help you to create nested tokens with ease. They are provided by the web-token/jwt-encryption
component. However, you must also install the following component to use it:
web-token/jwt-checker
web-token/jwt-signature
To instantiate the NestedTokenLoader
, you need a JWSLoader
and a JWELoader
.
Its use is very straightforward, you just have to call the method load
using the token, the encryption and signature key sets.
The last argument ($signature
in the following example) will represents the signature index of the verified signature. This is only useful when multiple signature support is used.
To instantiate the NestedTokenBuilderder
, you will need the following components:
a JWSBuilder
,
a JWEBuilder
,
a JWESerializerManager
,
a JWSSerializerManager
Its use is a bit more complicated than the loading as the nested token may be designed for several recipients or may have several signatures.
As a reminder, if one of the following parameter is set, the compact serialization mode cannot be used:
signature unprotected header,
JWE shared unprotected header,
recipient unprotected header,
Additional Authenticated Data.
Hereafter an example of a Symfony application configuration:
This configuration will create two public services:
jose.nested_token_loader.loader_1
jose.nested_token_builder.builder_1
These services can be called from the container (unless private) or injected in your services.
As any other services, you can create a nested token loader or builder from another bundle extension. The following bundle extension class will create the same configuration and services as above.
The Additional Authenticated Data (AAD) is an input to an Authenticated Encryption operation. The AAD is integrity protected but not encrypted.
Its value can be any string you want that is needed by your application. With the example below, we will add a dummy AAD:
Note: when the AAD is set, the Compact Serialization mode is not available.
You can easily check if an algorithm is fast enough on your platform. This project has tests for all operations with (almost) all algorithms.
To run those tests, you must install the library with all dev dependencies. When done, just run the following command:
The previous command will test ALL algorithms and may take more than 7 hours.
We recommend you to run tests only for the algorithm(s) you want to use. Just run the following command:
The value of GROUP
should be one of the following values:
All signature algorithms: JWS
All HMAC algorithms: hmac
HS256: HS256
HS384: HS384
HS512: HS512
All Elliptic Curves algorithms: ECDSA
ES256: ES256
ES384: ES384
ES512: ES512
All Edwards-curve algorithms: EdDSA
Ed25519: Ed25519
All RSA algorithms: RSASign
RS256: RS256
RS384: RS384
RS512: RS512
PS256: PS256
PS384: PS384
PS512: PS512
All key encryption algorithms: JWE
KW
A128KW: A128KW
A192KW: A192KW
A256KW: A256KW
GCMKW
A128GCMKW: A128GCMKW
A192GCMKW: A192GCMKW
A256GCMKW: A256GCMKW
ECDHES
ECDH-ES: ECDHES
ECDHESKW
ECDHESA128KW: ECDH-ES+A128KW
ECDHESA192KW: ECDH-ES+A192KW
ECDHESA256KW: ECDH-ES+A256KW
PBES2
PBES2-HS256+A128KW: PBES2HS256A128KW
PBES2-HS384+A192KW: PBES2HS384A192KW
PBES2-HS512+A256KW: PBES2HS512A256KW
RSAEnc
RSA1_5: RSA1_5
RSA-OAEP: RSA-OAEP
RSA-OAEP-256: RSA-OAEP-256
Note 1: the dir
algorithm is not tested as there is no key encryption or key decryption with this algorithm.
Note 2: tests consist in a full JWS/JWE creation and loading and sometimes using multiple key sizes.
Note 3: for JWE creation and loading, each key encryption algorithm is tested with the following content encryption algorithms:
A128GCM
, A192GCM
and A256GCM
A128CBC-HS256
, A192CBC-HS384
and A256CBC-HS512
Test all HMAC algorithms:
Test the RSA1_5 algorithm:
The result of the following command will only give you partial result. For example:
The main information is that the best algorithm takes only 31.275 µs... but you may need more information.
Just run the following command:
*The value of the --uuid
option is given at the end of the previous command. You can also use latest
.
A report.md
file will be created. It contains a detailed report (Markdown format). Example:
If it is not enough for you, you can get a full report with the following command:
The table hereafter is the result of all benchmarks with our development environment. It is given to help you to select the appropriate algorithms for your application.
The use of the algorithm ECDH-ES
with curves P-256
, P-384
or P-521
is not recommended on PHP7.1 or 7.2. The cryptographic operations with those curves are done using a pure PHP function and hence very slow.
The use of the RSA algorithms with a very long key (more that 4096 bits) is quite slow, but offers a good protection.
The PBES2* algorithms are quite slow, but also offer a good protection (see ). Default salt size (512 bits) and iterations (4096) and custom values (256/1024) used for the tests. Those values can be configured if needed.
As well as the , the encrypted tokens also have unprotected header. But with one difference: there are two unprotected headers:
Shared unprotected header applicable to all recipients.
Per-recipient unprotected header.
With the example below, we will create an encrypted token for two recipient and some unprotected header parameters:
The variable $jwe
will be a valid JWE object built for two recipients. The unprotected header parameter author
is applicable to the whole token while message
and description
are available only for the first and second recipient respectively.
Note: when an unprotected header is set, the Compact Serialization mode is not available.
When you need to encrypt the same payload for several audiences, you may want to do it at once. The JWE Builder supports multiple recipients.
With the example below, we will create an encrypted token for three different recipients using three different key encryption algorithms.
Important notes:
The content encryption algorithm MUST be the same for all recipients.
The Key Management Modes of the key encryption algorithms MUST be compatible (see table below).
Note: when an unprotected header is set, the Compact Serialization mode is not available.
Each Key Encryption Algorithm has its own Key Management Mode.
The allows the use of an unencoded payload for the signed tokens. This behaviour is interesting when your tokens have a detached payload and may reduce the token computation.
Please note that when the Compact Serialization mode is used, the characters of the payload must be limited to the following ASCII ranges:
From 0x20
to 0x2d
From 0x2f
to 0x7e
This feature is built in the framework and is enabled when the b64
header parameter is set to false
. As per the RFC, this header MUST be protected and also listed as a critical (crit
) header parameter.
Example:
As a remainder, both b64
and crit
parameters MUST be in the protected header.
Key Management Mode | Key Encryption | Key Wrapping | Direct Key Agreement | Key Agreement with Key Wrapping | Direct Encryption |
Key Encryption | YES | YES | NO | YES | NO |
Key Wrapping | YES | YES | NO | YES | NO |
Direct Key Agreement | NO | NO | NO | NO | NO |
Key Agreement with Key Wrapping | YES | YES | NO | NO | NO |
Direct Encryption | NO | NO | NO | NO | NO |
subject | groups | mean |
sign | JWS,EdDSA,Ed25519 | 139.323μs |
verify | JWS,EdDSA,Ed25519 | 169.125μs |
sign | JWS,ECDSA,ES256 | 139.144μs |
verify | JWS,ECDSA,ES256 | 223.170μs |
sign | JWS,ECDSA,ES384 | 941.535μs |
verify | JWS,ECDSA,ES384 | 1,075.417μs |
sign | JWS,ECDSA,ES512 | 504.271μs |
verify | JWS,ECDSA,ES512 | 826.615μs |
sign | JWS,hmac,HS256 | 19.593μs |
verify | JWS,hmac,HS256 | 24.045μs |
sign | JWS,hmac,HS384 | 20.061μs |
verify | JWS,hmac,HS384 | 24.672μs |
sign | JWS,hmac,HS512 | 19.838μs |
verify | JWS,hmac,HS512 | 24.935μs |
sign | JWS,none | 14.021μs |
verify | JWS,none | 17.317μs |
sign | JWS,RSASign,PS256 | 1,310.264μs |
verify | JWS,RSASign,PS256 | 121.113μs |
sign | JWS,RSASign,PS384 | 1,300.622μs |
verify | JWS,RSASign,PS384 | 119.065μs |
sign | JWS,RSASign,PS512 | 1,302.404μs |
verify | JWS,RSASign,PS512 | 117.445μs |
sign | JWS,RSASign,RS256 | 1,280.885μs |
verify | JWS,RSASign,RS256 | 106.382μs |
sign | JWS,RSASign,RS384 | 1,280.652μs |
verify | JWS,RSASign,RS384 | 297.263μs |
sign | JWS,RSASign,RS512 | 1,659.753μs |
verify | JWS,RSASign,RS512 | 119.476μs |
encryption/decryption | JWE,GCMKW,A128GCMKW | 63.022μs, 60.639μs, 58.909μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,GCMKW,A128GCMKW | 48.335μs, 50.021μs, 49.393μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption/decryption | JWE,GCMKW,A192GCMKW | 59.719μs, 59.396μs, 60.329μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,GCMKW,A192GCMKW | 48.432μs, 49.295μs, 50.244μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption/decryption | JWE,GCMKW,A256GCMKW | 60.966μs, 60.621μs, 59.821μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,GCMKW,A256GCMKW | 48.894μs, 49.165μs, 49.224μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption/decryption | JWE,KW,A128KW | 159.758μs, 176.995μs, 210.580μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,KW,A128KW | 93.752μs, 117.309μs, 162.917μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption/decryption | JWE,KW,A192KW | 137.808μs, 176.636μs, 214.446μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,KW,A192KW | 104.048μs, 122.472μs, 138.150μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption/decryption | JWE,KW,A256KW | 139.867μs, 176.727μs, 208.664μs (with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 respectively) |
encryption/decryption | JWE,KW,A256KW | 93.840μs, 115.313μs, 140.135μs (with A128GCM, A192GCM, A256GCM respectively) |
encryption | JWE,RSAEnc,RSA1_5 | from 178.368μs to 373.941μs (depending on the Content Encryption Algorithm and the key size) |
decryption | JWE,RSAEnc,RSA1_5 | from 354.921μs to 10,148.146μs (depending on the Content Encryption Algorithm and the key size) |
encryption | JWE,RSAEnc,RSA-OAEP | from 188.228μs to 428.624μs (depending on the Content Encryption Algorithm and the key size) |
decryption | JWE,RSAEnc,RSA-OAEP | from 381.853μs to 13,079.733μs (depending on the Content Encryption Algorithm and the key size) |
encryption | JWE,RSAEnc,RSA-OAEP-256 | from 195.231μs to 410.868μs (depending on the Content Encryption Algorithm and the key size) |
decryption | JWE,RSAEnc,RSA-OAEP-256 | from 354.090μs to 11,238.001μs (depending on the Content Encryption Algorithm and the key size) |
encryption/decryption | JWE,PBES2,PBES2HS256A128KW | from 2,109.175μs (256 bit salt / 1024 counts) to 7,943.047μs (512 bit salt / 4096 counts) |
encryption/decryption | JWE,PBES2,PBES2HS384A192KW | from 2,719.313μs (256 bit salt / 1024 counts) to 10,466.043μs (512 bit salt / 4096 counts) |
encryption/decryption | JWE,PBES2,PBES2HS256A128KW | from 2,746.634μs (256 bit salt / 1024 counts) to 10,600.124μs (512 bit salt / 4096 counts) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~45,198.922μs (with curve P-256) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~77,320.816μs (with curve P-384) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~120,709.648μs (with curve P-521) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~453.445μs (with curve X25519) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~21,249.059μs (with curve P-256) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~37,207.750μs (with curve P-384) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~57,072.871μs (with curve P-521) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA128KW | ~387.441μs (with curve X25519) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~44,697.707μs (with curve P-256) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~76,731.773μs (with curve P-384) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~124,164.813μs (with curve P-521) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~501.742μs (with curve X25519) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~21,603.676μs (with curve P-256) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~36,172.617μs (with curve P-384) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~55,530.465μs (with curve P-521) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA192KW | ~378.129μs (with curve X25519) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~44,701.426μs (with curve P-256) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~76,805.012μs (with curve P-384) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~121,017.648μs (with curve P-521) |
encryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~451.094μs (with curve X25519) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~21,335.781μs (with curve P-256) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~36,207.594μs (with curve P-384) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~55,440.664μs (with curve P-521) |
decryption | JWE,ECDHES,ECDHESKW,ECDHESA256KW | ~377.367μs (with curve X25519) |
encryption | JWE,ECDHES | ~44,762.633μs (with curve P-256) |
encryption | JWE,ECDHES | ~76,660.664μs (with curve P-384) |
encryption | JWE,ECDHES | ~119,539.141μs (with curve P-521) |
encryption | JWE,ECDHES | ~369.992μs (with curve X25519) |
decryption | JWE,ECDHES | ~21,894.422μs (with curve P-256) |
decryption | JWE,ECDHES | ~37,380.137μs (with curve P-384) |
decryption | JWE,ECDHES | ~58,231.930μs (with curve P-521) |
decryption | JWE,ECDHES | ~263.254μs (with curve X25519) |
Algorithm Key Management Mode | Key Encryption | Key Wrapping | Direct Key Agreement | Key Agreement with Key Wrapping | Direct Encryption |
dir | X |
A128KW | X |
A192KW | X |
A256KW | X |
ECDH-ES | X |
ECDH-ES+A128KW | X |
ECDH-ES+A192KW | X |
ECDH-ES+A256KW | X |
PBES2-HS256+A128KW | X |
PBES2-HS384+A192KW | X |
PBES2-HS512+A256KW | X |
RSA1_5 | X |
RSA-OAEP | X |
RSA-OAEP-256 | X |
A128GCMKW | X |
A192GCMKW | X |
A256GCMKW | X |
The following pages will help you to migrate your application to this project.
The JWE object, encryption algorithms and token serializers are part of the encryption component (web-token/jwt-encryption
). Claim and header checkers are decoupled and can be found in the checker component (web-token/jwt-checker
).
Why are encryption and checker components not together? The main reason is that when you issue encrypted tokens, you do not need any checker. Those components are decoupled to avoid the installation of unnecessary files.
The encryption and decryption processes have been completely reviewed.
In the examples below, we suppose we already have a JWK object ($key
).
Before
After
Before
After
Please note that it is important to check the token header before the decryption of the token. It will help you to reject tokens signed with unsupported algorithms or for other audiences.
As JWK, the JWKSet object is also part of the core component (web-token/jwt-core
). The constructor also changed in favor of a static method.
You can now create a key set using three ways:
Direct input of values (as before)
A list of JWK objects
A Json object string that represents a key set
Other important changes:
The JWKSet object does not implement \ArrayAccess
anymore. However, you still can iterate it (e.g. using foreach
).
The JWKSet is immutable. When you add a key, you will get a new object.
The method prependKey
has been removed.
You can select a key using parameters (key type, algorithm, key ID...)
Before
After
About The Key Selector
The key selector is able to find a key that fits on several requirements:
First argument: key used either for signature (sig
) or encryption (enc
).
Second argument: algorithm you would like to use. If the key has no alg
parameter but the key type allowed by the algorithm matches, then the key may be selected.
Third argument: an associated list of specific requirements. Can be any key parameter (e.g. kid
or custom parameter).
The method returns the key that matches best otherwise null
.
The following classes have been removed.
Jose\Object\JWKSets
Jose\Object\PublicJWKSet
Jose\Object\StorableJWKSet
Jose\Object\RotatableJWKSet
Jose\Object\JKUJWKSet
Jose\Object\X5UJWKSet
There is no replacement classes. The key set modification, rotation or the loading of distant keys (JKU/X5U) should now be done
through the dedicated console/standalone application (see this page),
using the JWKFactory
or JKUFactory
,
using a custom key manager.
If you use Symfony 3.4+, you will be able to load a keys and key sets using an environment variable and process it:
It the environment variables are valid keys and key sets, the associated parameters will converted as a JWK
or a JWKSet
object.
These parameters can be injected a usual:
Associated service configuration:
Please note that, contrary to the keys and key sets loaded through the configuration or the Configuration Helper, the one loaded through an environment variable are not listed in the Symfony Debug Toolbar.
Before
After
The use of this feature is drastically different. JKUFactory and X5UFactory are now services that relies on HttPlug to get the key sets.
Make sure the following dependencies are installed:
(web-token/jwt-bundle
and web-token/jwt-key-mgmt
) or web-token/jwt-framework
php-http/httplug-bundle
and at least one adapter (I will use php-http/guzzle6-adapter
here)
Do not forget to enable the associated bundles:
Create a request factory service
Configure the bundles:
When done, there are two possibilities to load JKU/X5U key sets:
Inject the Jose\Component\KeyManagement\JKUFactory
or Jose\Component\KeyManagement\X5UFactory
and call the loadFromUrl
method:
Configure a key set in the bundle configuration
The associated service will be jose.key_set.microsoft_keys
.
The JWS object, signature algorithms and token serializers are part of the signature component (web-token/jwt-signature
). Claim and header checkers are decoupled and can be found in the checker component (web-token/jwt-checker
).
Why are signature and checker components not together? The main reason is that when you issue signed tokens, you do not need any checker. Those components are decoupled to avoid the installation of unnecessary files.
The signature and loading processes have been completely reviewed.
In the examples below, we suppose we already have a JWK object ($key
).
Before
After
Before
After
Please note that it is important to check the token header before the verification of the signature. It will help you to reject tokens signed with unsupported algorithms.
The JWK object is part of the core component (web-token/jwt-core
). The may change concern the construction of the object. Its use is very similar.
Before
After
The following pages will help you to migrate from spomky-labs/jose and spomky-labs/jose-bundle to that new framework.
The claim checker manager is part of the checker component (web-token/jwt-checker
).
spomky-labs/jose
and this framework works a similar way thus migration is very easy. The main differences are:
There are two managers: one for the claims, one for the headers.
The manager only accepts an associative array. Conversion from a string to that array have to be done.
Checkers must implement the Jose\Component\Checker\ClaimChecker
interface.
Before
After
The computation of a JWE is done by the JWEBuilder
object. This object requires the following services:
an algorithm manager with key encryption algorithms
an algorithm manager with content encryption algorithms
a compression method manager. No compression method is needed if you do not intent to compress the payload
and a JSON converter.
Now let's create our first JWE object.
Great! If everything is fine you will get a JWE object with one recipient. We want to send it to the audience. Before that, it must be serialized.
We will use the compact serialization mode. This is the most common mode as it is URL safe and very compact. Perfect for a use in a web context!
All good! The variable $token
now contains a string that should be something like that: eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.9RLpf3Gauf05QPNCMzPcH4XNBLmH0s3e-YWwOe57MTG844gnc-g2ywfXt_R0Q9qsR6WhkmQEhdLk2CBvfqr4ob4jFlvJK0yW.CCvfoTKO9tQlzCvbAuFAJg.PxrDlsbSRcxC5SuEJ84i9E9_R3tCyDQsEPTIllSCVxVcHiPOC2EdDlvUwYvznirYP6KMTdKMgLqxB4BwI3CWtys0fceSNxrEIu_uv1WhzJg.4DnyeLEAfB4I8Eq0UobnP8ymlX1UIfSSADaJCXr3RlU
.
The header checker manager is part of the checker component (web-token/jwt-checker
).
spomky-labs/jose
and this framework works a similar way thus migration is very easy. The main differences are:
There are two managers: one for the claims, one for the headers.
The manager needs at least one Token Support handler.
You will find JWS
and JWE
Token Supports in the web-token/jwt-signature
and web-token/jwt-encryption
components respectively.
Checkers must implement the Jose\Component\Checker\HeaderChecker
interface.
Before
After
Please note that the header crit
is always checked.