# Introduction

This document is available online at <https://web-token.spomky-labs.com>.

## JWT Framework

This framework provides an implementation of:

* JW**S** [JSON Web Signature (RFC 7515)](https://tools.ietf.org/html/rfc7515),
* JW**T** [JSON Web Token (RFC 7519)](https://tools.ietf.org/html/rfc7519),
* JW**E** [JSON Web Encryption (RFC 7516)](http://tools.ietf.org/html/rfc7516),
* JW**A** [JSON Web Algorithms (RFC 7518)](http://tools.ietf.org/html/rfc7518).
* JW**K** [JSON Web Key (RFC 7517)](http://tools.ietf.org/html/rfc7517).
* JSON Web Key Thumbprint ([RFC 7638](https://tools.ietf.org/html/rfc7638)).
* Unencoded Payload Option [RFC7797](https://tools.ietf.org/html/rfc7797).

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.

## Provided Features

### Supported Input Types:

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](https://tools.ietf.org/html/rfc7515#appendix-F) is supported.

### Supported Serialization Modes

* Compact JSON Serialization Syntax for JWS and JWE
* Flattened JSON Serialization Syntax for JWS and JWE
* General JSON Serialization Syntax for JWS and JWE

### Supported Compression Methods

| 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* |

### Supported Key Types (JWK)

| 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  |

JWK objects support JSON Web Key Thumbprint ([RFC 7638](https://tools.ietf.org/html/rfc7638)).

*Note: we use a* `none` *key type for the* `none` *algorithm only.*

### Key Sets (JWKSet)

JWKSet is fully supported.

### Supported Signature Algorithms

| 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       | [With PHP 7.1, third party extension highly recommended](https://github.com/jedisct1/libsodium-php)        |
| 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.** |

### Supported Key Encryption Algorithms

| 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       | [With PHP 7.1, third party extension highly recommended](https://github.com/jedisct1/libsodium-php) |
| 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.**                                              |

### Supported Content Encryption Algorithms

| 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.** |

## Prerequisites

This framework needs at least:

* ![PHP 7.1+](https://img.shields.io/badge/PHP-7.1%2B-ff69b4.svg),
* 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](https://github.com/jedisct1/libsodium-php)

## Continuous Integration

It has been successfully tested using `PHP 7.1`, `PHP 7.2` and `nightly` with all algorithms.

Tests vectors from the [RFC 7520](http://tools.ietf.org/html/rfc7520) 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](https://scrutinizer-ci.com/g/web-token/jwt-framework) and [Sensio Insight](https://insight.sensiolabs.com/projects/b7efa68f-8962-41cf-a2e3-4444426bc95a).

Coding Standards are verified by [StyleCI](https://styleci.io/repos/105997386).

Code coverage is analyzed by [Coveralls.io](https://coveralls.io/github/web-token/jwt-framework).

## How to use

* [The components](/1.x/components)
* [The bundles](/1.x/symfony-bundle)
* [The console commands](/1.x/console)

## Security Recommendations

**To avoid security issues on your application, please follow these** [**Security Recommendations**](/1.x/security-recommendations) **carefully**.

## Performances

Please read the [performance page](/1.x/benchmarks) to know how to test the algorithms of the framework.

You can also see the [last benchmarks](/1.x/benchmarks/result-table) made with our development environment.

## Contributing

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](https://github.com/web-token/jwt-framework/labels/help+wanted) or [those that are easy to fix](https://github.com/web-token/jwt-framework/labels/easy-pick).

Do not forget to [follow these best practices](https://github.com/web-token/jwt-framework/tree/master/.github/CONTRIBUTING.md).

**If you think you have found a security issue, DO NOT open an issue**. [You MUST submit your issue here](https://gitter.im/Spomky/).

## Licence

This project is release under [MIT licence](https://github.com/web-token/jwt-framework/tree/846e8752fef1f7276488f52f80e69fcef54f8acc/LICENSE.md).


# Components

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.

* [Algorithm Management](/1.x/components/algorithm-management-jwa)
* [Header Checker](/1.x/components/header-checker) and [Claim Checker](/1.x/components/claim-checker)&#x20;
* [Keys and key sets](/1.x/components/key-jwk-and-key-set-jwkset)

When your algorithm manager, your keys and your checkers are ready, you will be able to create or load your first tokens.

* [Signed tokens](/1.x/components/signed-tokens-jws)
* [Encrypted tokens](/1.x/components/encrypted-tokens-jwe)


# Algorithm Management (JWA)

The algorithm management is part of the `web-token/jwt-core` component:

```bash
composer require web-token/jwt-core
```

## Algorithm Manager

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](/1.x/components/signed-tokens-jws) or the [Encrypted tokens](/1.x/components/encrypted-tokens-jwe) 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`

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\ES512;

$algorithm_manager = AlgorithmManager::create([
    new PS256(),
    new ES512(),
]);
```

*It is not possible to set the same algorithm twice in the same algorithm manager.*

## Algorithm Manager Factory

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.

```php
<?php

use Jose\Component\Core\AlgorithmManagerFactory;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS512A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;

$algorithm_manager_factory = new AlgorithmManagerFactory();
$algorithm_manager_factory
    ->add('PS256', new PS256())
    ->add('A128CBC-HS256', new A128CBCHS256())
    ->add('PBES2-HS512+A256KW', new PBES2HS512A256KW())
    ->add('PBES2-HS512+A256KW with custom configuration', new PBES2HS512A256KW(128, 8192))
;
```

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`:

```php
<?php

$signature_algorithm_manager = $algorithm_manager_factory->create(['PS256']);
$encryption_algorithm_manager = $algorithm_manager_factory->create(['A128CBC-HS256', 'PBES2-HS512+A256KW']);
$encryption_algorithm_manager_for_paranoid = $algorithm_manager_factory->create(['A128CBC-HS256', 'PBES2-HS512+A256KW with custom configuration']);
```


# Key (JWK) and Key Set (JWKSet)

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:

```bash
composer require web-token/jwt-core
```

## JWK

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](/1.x/components/key-jwk-and-key-set-jwkset/key-management) to know how to create your keys.

## JWKSet

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](/1.x/components/key-jwk-and-key-set-jwkset/key-set-management) to know how to create and use the key sets.


# Key Management (JWK)

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.

```php
<?php
// Check if the key has a parameter.
$jwk->has('kty');

// Retrieve the key parameter.
$jwk->get('kty');

// Retrieve all key parameters.
$jwk->all();

// Calculate the thumbprint of the key. Acceptable hash algorithms are those returned by the PHP function "hash_algos".
$jwk->thumbprint('sha256');

// If the key is a private key (RSA, EC, OKP), it can be converted into public:
$public_key = $jwk->toPublic();

// The JWK object can be serialized into JSON
json_encode($jwk);
```

**Please note a JWK object is an immutable object**

## Generate A New Key

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.

```bash
composer require web-token/jwt-key-mgmt
```

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.*

### Octet String

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).

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createOctKey(
    1024, // Size in bits of the key. We recommend at least 128 bits.
    [
        'alg' => 'HS256', // This key must only be used with the HS256 algorithm
        'use' => 'sig'    // This key is used for signature/verification operations only
    ]
);
```

> 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:

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$jwk = JWKFactory::createFromSecret(
    'My Secret Key',       // The shared secret
    [                      // Optional additional members
        'alg' => 'HS256',
        'use' => 'sig'
    ]
);
```

### RSA Key Pair

The following example will show you how to create a `RSA` key.

The key size must be of 384 bits at least.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$private_key = JWKFactory::createRSAKey(
    4096, // Size in bits of the key. We recommend at least 2048 bits.
    [
        'alg' => 'RSA-OAEP-256', // This key must only be used with the RSA-OAEP-256 algorithm
        'use' => 'enc'    // This key is used for encryption/decryption operations only
    ]);
```

### Elliptic Curve Key Pair

The following example will show you how to create a `EC` key.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createECKey('P-256');
```

The supported curves are:

* `P-256`
* `P-384`
* `P-521` (note that this is **521** and not 512)

#### Octet Key Pair

The following example will show you how to create a `OKP` key.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createOKPKey('X25519');
```

The supported curves are:

* `Ed25519` for signature/verification only
* `X25519` for encryption/decryption only

### None Key

The `none` key type is a special type used only for the `none` algorithm.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createNoneKey();
```

## Create Key From External Sources

### From Values

In case you already have key values, you can create a key by passing those values as an argument:

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromValues([
    'kid' => '71ee230371d19630bc17fb90ccf20ae632ad8cf8',
    'kty' => 'RSA',
    'alg' => 'RS256',
    'use' => 'sig',
    'n' => 'vnMTRCMvsS04M1yaKR112aB8RxOkWHFixZO68wCRlVLxK4ugckXVD_Ebcq-kms1T2XpoWntVfBuX40r2GvcD9UsTFt_MZlgd1xyGwGV6U_tfQUll5mKxCPjr60h83LXKJ_zmLXIqkV8tAoIg78a5VRWoms_0Bn09DKT3-RBWFjk=',
    'e' => 'AQAB',
]);
```

### From A Key File

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.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromKeyFile(
    '/path/to/my/key/file.pem', // The filename
    'Secret',                   // Secret if the key is encrypted
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

### From A PKCS#12 Certificate

You can convert a PKCS#12 Certificate into a JWK. Encrypted certificates are also supported.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromPKCS12CertificateFile(
    '/path/to/my/key/file.p12', // The filename
    'Secret',                   // Secret if the key is encrypted
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

### From A X.509 Certificate

You can convert a X.509 Certificate into a JWK.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromCertificateFile(
    '/path/to/my/key/file.crt', // The filename
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

*Please note that X.509 certificates only contains public keys*.


# Key Set Management (JWKSet)

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**

```php
<?php
// Returns all keys
$jwkset->all();

// Check if the key set has the key with the key ID 'KEY ID'.
$jwkset->has('KEY ID');

// Retreive the key with the key ID 'KEY ID'.
$jwkset->get('KEY ID');

// Counts the keys in the key set.
$jwkset->count(); // The method count($jwkset) has the same behaviour.

// Adds a key to the key set.
// /!\ As the JWKSet object is immutable, this method will create a new key set. The previous key set is unchanged.
$new_jwkset = $jwkset->with($jwk);

// Removes a key to the key set.
// /!\ As the JWKSet object is immutable, this method will create a new key set. The previous key set is unchanged.
$new_jwkset = $jwkset->without('KEY ID');

// Selects a key according to the requirements.
// The first argument is the key usage ("sig" of "enc")
// The second argument is the algorithm to be used (optional)
// The third argument is an associative array this constraints (optional)
$key = $jwkset->selectKey('sig', $algorithm, ['kid' => 'KEY ID']);

// You can iterate on a key set
foreach($jwkset as $kid => $jwk) {
    // Action with the key done here
}

// The JWKSet object can be serialized into JSON
json_encode($jwkset);
```

*We recommend you to avoid mixing public, private or shared keys in the same key set*.


# Header Checker

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:

```bash
composer require web-token/jwt-checker
```

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.&#x20;

## Header Checker 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.

```php
<?php

use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Signature\JWSTokenSupport;

$headerCheckerManager = HeaderCheckerManager::create(
    [
        new AlgorithmChecker(['HS256']), // We check the header "alg" (algorithm)
    ],
    [
        new JWSTokenSupport(), // Adds JWS token type support
    ]
);
```

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.

```php
$headerCheckerManager->check($jwt, 0);
```

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.

```php
$headerCheckerManager->check($jwt, 0, ['alg', 'enc', 'crit']);
```

## Header Checker Manager Factory

The Header Checker Manager Factory will help you to create as many Header Checker Manager as you want to fit on your application requirements.

```php
<?php

use Jose\Component\Checker\HeaderCheckerManagerFactory;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Encryption\JWETokenSupport;
use Jose\Component\Signature\JWSTokenSupport;

$headerCheckerManagerFactory = new HeaderCheckerManagerFactory();
$headerCheckerManagerFactory
    ->add('signature_alg', new AlgorithmChecker(['HS256']))
    ->add('key_encryption_alg', new AlgorithmChecker(['RSA1_5']))
    ->addTokenTypeSupport(new JWSTokenSupport())
    ->addTokenTypeSupport(new JWETokenSupport());

$headerCheckerManagerForSignatures = $headerCheckerManagerFactory->create(['signature_alg']);
$headerCheckerManagerForEncryption = $headerCheckerManagerFactory->create(['key_encryption_alg']);
```

## Custom Header Checker

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](https://tools.ietf.org/html/rfc7519#section-5.3)
* `UnencodedPayloadChecker`: checks the `b64` header parameter. See [unencoded payload](/1.x/advanced-topics/signed-tokens-and/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`.

```php
<?php

namespace Acme\Checker;

use Jose\Component\Checker\HeaderChecker;
use Jose\Component\Checker\InvalidHeaderException;

/**
 * Class CustomChecker.
 */
final class CustomChecker implements HeaderChecker
{
    public function checkHeader($value)
    {
        if (!is_array($value) || !in_array($value, ['foo', 'bar'])) {
            throw new InvalidHeaderException('Invalid header "custom".', 'custom', $value);
        }
    }

    // This header parameter name.
    public function supportedHeader(): string
    {
        return 'custom';
    }

    // This method indicates if this parameter must be in the protected header or not.
    public function protectedHeaderOnly(): bool
    {
        return true;
    }
}
```


# Claim Checker

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:

```bash
composer require web-token/jwt-checker
```

## Claim Checker Manager

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.

```php
<?php

use Jose\Component\Checker\ClaimCheckerManager;
use Jose\Component\Checker;

$claimCheckerManager = ClaimCheckerManager::create(
    [
        new Checker\IssuedAtChecker(),
        new Checker\NotBeforeChecker(),
        new Checker\ExpirationTimeChecker(),
        new Checker\AudienceChecker('Audience'),
    ]
);
```

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.

```php
use Jose\Component\Core\Converter\StandardConverter;

$jsonConverter = new StandardConverter();

$claims = $jsonConverter->decode($jwt->getPayload());
$claimCheckerManager->check($claims);
```

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.

```php
$claimCheckerManager->check($claims, ['iss', 'sub', 'aud']);
```

## Custom Claim Checker

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`;

```php
<?php

declare(strict_types=1);

namespace Acme\Checker;

use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\InvalidClaimException;

/**
 * Class FooChecker.
 */
final class FooChecker implements ClaimCheckerInterface
{
    /**
     * {@inheritdoc}
     */
    public function checkClaim($value)
    {
        if (!is_string($value)) { // If the value is not a string, then we throw an exception
            throw new InvalidClaimException('The claim "foo" must be a string.', 'foo', $value);
        }
        if (!in_array($value, ['bar', 'bat'])) { // Check if the value is allowed
            throw new InvalidClaimException('The claim "foo" must be "bar" or "bat".', 'foo', $value);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function supportedClaim(): string
    {
        return 'foo'; //The claim to check.
    }
}
```

All done! Now you can instantiate your class and add it to your Claim Checker Manager.

## Replicating Claims as Header Parameters

The [RFC7516 section 5.3](https://tools.ietf.org/html/rfc7519#section-5.3) 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 [custom header checker](/1.x/components/header-checker). However, to avoid duplicated classes, your claim checker can implement the `Jose\Component\Checker\HeaderChecker` interface.

Have a look at the `IssuedAtChecker` or the `NotBeforeChecker` classes. These checkers can be used for claim and header checks.

## Claim Checker Manager Factory

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.

```php
<?php

use Jose\Component\Checker\ClaimCheckerManagerFactory;
use Jose\Component\Checker;

$claimCheckerManagerFactory = new ClaimCheckerManagerFactory();
$claimCheckerManagerFactory
    ->add('iat', new Checker\IssuedAtChecker())
    ->add('nbf', new Checker\NotBeforeChecker())
    ->add('exp', new Checker\ExpirationTimeChecker())
    ->add('aud1', new Checker\AudienceChecker('Audience for service #1'))
    ->add('aud2', new Checker\AudienceChecker('Audience for service #2'));

$claimCheckerManager1 = $claimCheckerManagerFactory->create(['iat', 'exp', 'aud2']);
$claimCheckerManager2 = $claimCheckerManagerFactory->create(['aud1', 'exp']);
```


# Signed Tokens (JWS)

To use the signed tokens (JWS), you have to install the [`web-token/jwt-signature` component](https://github.com/web-token/jwt-signature).

```bash
composer require web-token/jwt-signature
```

This component provides lot of signature algorithms and classes to load and create signed tokens.

Please refer to [this signature algorithm table](/1.x/components/signed-tokens-jws/signature-algorithms) to know what algorithms are available.

Then, you will find an [example to create a signed token here](/1.x/components/signed-tokens-jws/jws-creation) and another [example to load and verify](/1.x/components/signed-tokens-jws/jws-loading) incoming tokens.


# Signature Algorithms

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.

## How To Use

These algorithms have to be used with the [Algorithm Manager](/1.x/components/algorithm-management-jwa). They do not need any arguments.

Example:

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\ES512;
use Jose\Component\Signature\Algorithm\None;

$algorithm_manager = AlgorithmManager::create([
    new PS256(),
    new ES512(),
    new None(),
]);
```


# JWS Creation

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.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = AlgorithmManager::create([
    new HS256(),
]);

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// We instantiate our JWS Builder.
$jwsBuilder = new JWSBuilder(
    $jsonConverter,
    $algorithmManager
);
```

Now let's create our first JWS object.

```php
// The payload we want to sign. The payload MUST be a string hence we use our JSON Converter.
$payload = $jsonConverter->encode([
    'iat' => time(),
    'nbf' => time(),
    'exp' => time() + 3600,
    'iss' => 'My service',
    'aud' => 'Your application',
]);

$jws = $jwsBuilder
    ->create()                               // We want to create a new JWS
    ->withPayload($payload)                  // We set the payload
    ->addSignature($jwk, ['alg' => 'HS256']) // We add a signature with a simple protected header
    ->build();                               // We build it
```

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!

```php
use Jose\Component\Signature\Serializer\CompactSerializer;

$serializer = new CompactSerializer($jsonConverter); // The serializer

$token = $serializer->serialize($jws, 0); // We serialize the signature at index 0 (we only have one signature).
```

All good! The variable `$token` now contains a string that should be something like this:

```
eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDc4OTY5OTIsIm5iZiI6MTUwNzg5Njk5MiwiZXhwIjoxNTA3OTAwNTkyLCJpc3MiOiJNeSBzZXJ2aWNlIiwiYXVkIjoiWW91ciBhcHBsaWNhdGlvbiJ9.eycp9PTdgO4WA-68-AMoHPwsKDr68NhjIQKz4lUkiI0
```

Other serialization modes exist. We will see them in the Advanced Topics section.


# JWS Loading

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.

## Serializer And Verifier

In the following example, we will try to load a signed token. We will only use the `HS256` algorithm.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSVerifier;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = AlgorithmManager::create([
    new HS256(),
]);

// We instantiate our JWS Verifier.
$jwsVerifier = new JWSVerifier(
    $algorithmManager
);
```

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.**

```php
<?php

use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\Serializer\CompactSerializer;

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// The serializer manager. We only use the JWS Compact Serialization Mode.
$serializerManager = JWSSerializerManager::create([
    new CompactSerializer($jsonConverter),
]);

// The input we want to check
$token = 'eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDc4OTY5OTIsIm5iZiI6MTUwNzg5Njk5MiwiZXhwIjoxNTA3OTAwNTkyLCJpc3MiOiJNeSBzZXJ2aWNlIiwiYXVkIjoiWW91ciBhcHBsaWNhdGlvbiJ9.eycp9PTdgO4WA-68-AMoHPwsKDr68NhjIQKz4lUkiI0';

// We try to load the token.
$jws = $serializerManager->unserialize($token);

// We verify the signature. This method does NOT check the header.
// The arguments are:
// - The JWS object,
// - The key,
// - The index of the signature to check. See 
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);
```

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.

## JWSLoader Object

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.

```php
<?php

use Jose\Component\Signature\JWSLoader;

$jwsLoader = new JWSLoader(
    $serializerManager,
    $jwsVerifier,
    $headerCheckerManager
);

$jws = $jwsLoader->loadAndVerifyWithKey($token, $jwk, $signature, $payload);
```

In case you use a key set, you can use the method `loadAndVerifyWithKeySet`.

## JWSLoaderFactory Object

> 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)

```php
<?php

use Jose\Component\Signature\JWSLoaderFactory;

$jwsLoaderFactory = new JWSLoaderFactory(
    $jwsSerializerManagerFactory,
    $jwsVerifierFactory,
    $headerCheckerManagerFactory
);

$jwsLoader = $jwsLoaderFactory->create(
    ['jws_compact'], // List of serializer aliases
    ['HS256'],       // List of signature algorithm aliases
    ['alg']          // Optional list of header checker aliases
);
```


# Encrypted Tokens (JWE)

To use the encrypted tokens (JWE), you have to install the [`web-token/jwt-encryption` component](https://github.com/web-token/jwt-encryption).

```bash
composer require web-token/jwt-encryption
```

This component provides lot of encryption algorithms and classes to load and create encrypted tokens.

Please refer to [this encryption algorithm table](/1.x/components/encrypted-tokens-jwe/encryption-algorithms) to know what algorithms are available.

Then, you will find an [example to create an encrypted token here](/1.x/components/encrypted-tokens-jwe/jwe-creation) and another [example to load and decrypt](/1.x/components/encrypted-tokens-jwe/jwe-loading) incoming tokens.


# Encryption Algorithms

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](https://en.wikipedia.org/wiki/Adaptive_chosen-ciphertext_attack).
* 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.

## How To Use

These algorithms have to be used with the [Algorithm Manager](/1.x/components/algorithm-management-jwa). They do not need any arguments.

Example:

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A128KW;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;

$algorithmManager = AlgorithmManager::create([
    new A128KW(),
    new PBES2HS256A128KW(),
    new A128CBCHS256(),
]);
```

By default, `PBES2*` algorithms use the following parameter values:

* Salt size: 64 bytes (512 bits)
* Count: 4096&#x20;

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:

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW;

$algorithmManager = AlgorithmManager::create([
    new PBES2HS256A128KW(16, 1024),
]);
```


# JWE Creation

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.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEBuilder;

// The key encryption algorithm manager with the A256KW algorithm.
$keyEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256KW(),
]);

// The content encryption algorithm manager with the A256CBC-HS256 algorithm.
$contentEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256CBCHS512(),
]);

// The compression method manager with the DEF (Deflate) method.
$compressionMethodManager = CompressionMethodManager::create([
    new Deflate(),
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// We instantiate our JWE Builder.
$jweBuilder = new JWEBuilder(
    $jsonConverter,
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);
```

Now let's create our first JWE object.

```php
use Jose\Component\Core\JWK;

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The payload we want to encrypt. The payload MUST be a string hence we use our JSON Converter.
$payload = $jsonConverter->encode([
    'iat' => time(),
    'nbf' => time(),
    'exp' => time() + 3600,
    'iss' => 'My service',
    'aud' => 'Your application',
]);

$jwe = $jweBuilder
    ->create()              // We want to create a new JWE
    ->withPayload($payload) // We set the payload
    ->withSharedProtectedHeader([
        'alg' => 'A256KW',        // Key Encryption Algorithm
        'enc' => 'A256CBC-HS512', // Content Encryption Algorithm
        'zip' => 'DEF'            // We enable the compression (irrelevant as the payload is small, just for the example).
    ])
    ->addRecipient($jwk)    // We add a recipient (a shared key or public key).
    ->build();              // We build it
```

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!

```php
use Jose\Component\Encryption\Serializer\CompactSerializer;

$serializer = new CompactSerializer($jsonConverter); // The serializer

$token = $serializer->serialize($jwe, 0); // We serialize the recipient at index 0 (we only have one recipient).
```

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`.


# JWE Loading

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](/1.x/components/encrypted-tokens-jwe/jwe-creation).

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;

// The key encryption algorithm manager with the A256KW algorithm.
$keyEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256KW(),
]);

// The content encryption algorithm manager with the A256CBC-HS256 algorithm.
$contentEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256CBCHS512(),
]);

// The compression method manager with the DEF (Deflate) method.
$compressionMethodManager = CompressionMethodManager::create([
    new Deflate(),
]);

// We instantiate our JWE Decrypter.
$jweDecrypter = new JWEDecrypter(
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);
```

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.**

```php
<?php

use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Encryption\Serializer\CompactSerializer;

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// The serializer manager. We only use the JWE Compact Serialization Mode.
$serializerManager = JWESerializerManager::create([
    new CompactSerializer($jsonConverter),
]);

// The input we want to decrypt
$token = 'eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.9RLpf3Gauf05QPNCMzPcH4XNBLmH0s3e-YWwOe57MTG844gnc-g2ywfXt_R0Q9qsR6WhkmQEhdLk2CBvfqr4ob4jFlvJK0yW.CCvfoTKO9tQlzCvbAuFAJg.PxrDlsbSRcxC5SuEJ84i9E9_R3tCyDQsEPTIllSCVxVcHiPOC2EdDlvUwYvznirYP6KMTdKMgLqxB4BwI3CWtys0fceSNxrEIu_uv1WhzJg.4DnyeLEAfB4I8Eq0UobnP8ymlX1UIfSSADaJCXr3RlU';

// We try to load the token.
$jwe = $serializerManager->unserialize($token);

// We decrypt the token. This method does NOT check the header.
$jwe = $jweDecrypter->decryptUsingKey($jwe, $jwk);
```

OK so if not exception is thrown, then your token is loaded and the payload correctly decrypted.

## JWELoader Object

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.

```php
<?php

use Jose\Component\Encryption\JWELoader;

$jweLoader = new JWELoader(
    $serializerManager,
    $jweDecrypter,
    $headerCheckerManager
);

$jwe = $jweLoader->loadAndDecryptWithKey($token, $key, $recipient);
```

In case you use a key set, you can use the method `loadAndDecryptWithKeySet`.

## JWELoaderFactory Object

> 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)

```php
<?php

use Jose\Component\Encryption\JWELoaderFactory;

$jweLoaderFactory = new JWELoaderFactory(
    $jweSerializerManagerFactory,
    $jweDecrypterFactory,
    $headerCheckerManagerFactory
);

$jweLoader = $jweLoaderFactory->create(
    ['jwe_compact'], // List of serializer aliases
    ['A128KW'],      // List of key encryption algorithm aliases
    ['A128KW'],      // List of content encryption algorithm aliases
    ['DEF'],         // List of compression method aliases
    ['alg', 'enc']   // Optional list of header checker aliases
);
```


# Symfony Bundle

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:

```php
/**
 * {@inheritdoc}
 */
public function registerBundles()
{
    $bundles = [
        ...
        new Jose\Bundle\JoseFramework\JoseFrameworkBundle(),
    ];

    return $bundles;
}
```

The bundle capabilities will depend on the components installed in your application. The core component is always available.

* [Algorithm Management](/1.x/symfony-bundle/algorithm-management)
* [Header and Claim Checkers](/1.x/symfony-bundle/header-and-claim-checker-management)
* [Keys and key sets](/1.x/symfony-bundle/key-and-key-set-management)
* [Signed tokens](/1.x/symfony-bundle/signed-tokens)
* [Encrypted tokens](/1.x/symfony-bundle/encrypted-tokens)


# Algorithm Management

## Algorithm Manager Factory Service

The Symfony Bundle provides an Algorithm Manager Factory service. The available algorithms depends on the components installed on your application.

```php
<?php

use Jose\Component\Core\AlgorithmManagerFactory;

$algorithmManagerFactory = $container->get(AlgorithmManagerFactory::class);
$algorithmManager = $algorithmManagerFactory->create(['RS256', 'HS512']);
```

## Custom Algorithm

This factory handles all algorithms services tagged with `jose.algorithm`.

Example:

```yaml
services:
    Acme\Bundle\Algorithm\FooAlgorihtm:
        tags:
            - {'name': 'jose.algorithm', 'alias': 'FOO'}
```

Your algorithm will be available through the algorithm manager factory service and the alias `FOO`.

## PBES2-\* Algorithms

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:

```yaml
services:
    Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW:
        arguments:
            - 128   # salt size
            - 10240 # counts
        tags:
            - {'name': 'jose.algorithm', 'alias': 'Ultra-Secured PBES2-HS256+A128KW'}
```

You can now use your custom alias:

```php
$algorithmManager = $algorithmManagerFactory->create(['Ultra-Secured PBES2-HS256+A128KW']);
```


# Key and Key Set Management

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:

```yaml
parameters:
    my_private_key: '%env(jwk:MY_PRIVATE_KEY)%'
    my_public_keyset: '%env(jwkset:MY_PUBLIC_KEYSET)%'
```

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:

```bash
composer require web-token/jwt-key-mgmt
```

* [Key Management (JWK)](/1.x/symfony-bundle/key-and-key-set-management/key-management-jwk)
* [Key Set Management (JWKSet)](/1.x/symfony-bundle/key-and-key-set-management/key-set-management-jwkset)


# Key Management (JWK)

## Key Management (JWK)

## Keys As Services

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:

```yaml
jose: # Configuration of the JWT Framework
    keys: # Configuration of the keys
        key_name: # Unique key name
            method_name: # Name of the method
                ...
                is_public: true
```

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.

### From A Shared Secret

> This feature was introduced in version 1.1.

This method will directly get a shared secret.

```yaml
jose:
    keys:
        key_name:
            secret: # Method
                secret: 'This is my shared secret'
                additional_values:
                    use: 'sig'
                    alg: 'RS512'
```

### From A JWK Object

This method will directly load a JWK object.

```yaml
jose:
    keys:
        key_name:
            jwk: # Method
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
```

### From A X509 Certificate File

This method will load a X509 Certificate file.

```yaml
jose:
    keys:
        key_name:
            certificate: # Method
                path: '/path/to/your/X509/certificate'
                additional_values: # Optional values
                    use: 'sig'
                    alg: 'RS256'
```

### From A X509 Certificate

This method will load a key from a X509 Certificate.

```yaml
jose:
    keys:
        key_name:
            x5c: # Method
                value: '-----BEGIN CERTIFICATE----- ....'
                additional_values: # Optional values.
                    use: 'sig'
                    alg: 'RS256'
```

### From A PKCS#1/PKCS#8 Key File

This method will load a key from a PKCS#1 or PKCS#8 key file.

```yaml
jose:
    keys:
        key_name:
            file: # Method
                path: '/path/to/your/key/file'
                password: 'secret' # Optional. Only if the key is encrypted
                additional_values: # Optional values.
                    use: 'sig'
                    alg: 'RS256'
```

### From A Key In A Key Set

This method will retrieve a key from a JWKSet service.

```yaml
jose:
    keys:
        key_name:
            jwkset: # Method
                key_set: 'jose.key_set.my_key_set' # JWKSet service
                index: 0 # Use key at index 0
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        key_name:
            jwk: # Method
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Key Set Management (JWKSet)

## Key Set Management (JWKSet)

## Key Sets As Services

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:

```yaml
jose: # Configuration of the JWT Framework
    key_sets: # Configuration of the keys
        keyset_name: # Unique key name
            method_name: # Name of the method
                ...
                is_public: true
```

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.

### From A JWKSet Object

This method will directly get a JWKSet object.

```yaml
jose:
    key_sets:
        key_name:
            jwkset: # Method
                value: '{"keys":[{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"},{"kty":"oct","k":"bwIAv5Nn-fo8p4LCEvM4IR9eLXgzJRs8jXCLb3xR0tDJGiZ46KheO4ip6htFKyN2aqJqlNi9-7hB6I1aLLy1IRT9-vcBoCSGu977cNAUuRLkRp7vo8s6MsxhB8WvQBDRZghV7jIYaune-3vbE7iDU2AESr8BUtorckLoO9uW__fIabaa3hJMMQIHCzYQbJKZvlCRCKWMk2H_zuS4JeDFTvyZH1skJYF_TET1DrCZHMPicw-Yk3_m2P-ilC-yidPPoVzeU8Jj3tQ6gtX3975qiQW7pt2qbgjKAuq2wsz_9hxLBtMB5rQPafFoxop7O4BklvZ9-ECcK6dfI2CAx9_tjQ"}]}'
```

### Distant Key Sets

You can load key sets shared by a distant service (e.g. Google, Microsoft, Okta...). You must install and enable the [Httplug Bundle](http://docs.php-http.org/en/latest/integrations/symfony-bundle.html).

When done, you have to create a client and enable the JKU Factory service by indicating the request factory service to use:

```yaml
httplug: # Example of client configuration
    plugins:
        cache: # We use the cache plugin
            cache_pool: 'cache.app' # We use the PSR-6 Cache service of the application
            config:
                default_ttl: 1800 # TTL set to 30 min
    clients:
        acme:
            factory: 'httplug.factory.guzzle6'
            plugins: ['httplug.plugin.cache'] # We enable the cache plugin for that client.

jose:
    jku_factory:
        enabled: true
        client: 'httplug.client.acme' # The Httplug client
        request_factory: 'httplug.message_factory' # In general, you will use the same message factory as the one used by Httplug
```

**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.

#### From A JKU (JWK Url)

The following example will allow you tu load a key set from a distant URI. The key set must be a JWKSet object.

```yaml
jose:
    key_sets:
        key_name:
            jku: # Method
                url: 'https://login.microsoftonline.com/common/discovery/keys'
```

#### From A X5U (X509 Certificates Url)

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.

```yaml
jose:
    key_sets:
        key_name:
            x5u: # Method
                url: 'https://www.googleapis.com/oauth2/v1/certs'
```

## Shared Ket Sets

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.

```yaml
jwkset_endpoints:
    resource: "@JoseFrameworkBundle/Resources/config/routing/jwkset_controller.yml"
```

Then you can share your key set.

```yaml
jose:
    key_sets:
        public_keyset: # The key set we want to share
            jwkset:
                value: '{"keys":[{"kty":"OKP","crv":"X25519","x":"ovuZiVcMXBN4r0VgCvJy_ChAsBv4YPJGC5w56PzndXY"},{"kty":"OKP","crv":"X25519","x":"4qyOJ4T9RkdciIn6LDxb2LdM1Ov-dtBSuj0jh6nCuyc"}]}'
    jwk_uris:
        shared_keyset:
            id: 'jose.key_set.public_keyset' # The key set service to share
            path: '/certs' # Path of the key set. Final path is hostname/route_prefix/path: https://www.foo.com/keys/certs
            max_age: 1000 # Set the HTTP cache max age of this key set
```

Now went you go to the URL `http://128.0.0.1:8000/certs`, you will get your key set.

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    key_sets:
        key_name:
            jku: # Method
                url: 'https://login.microsoftonline.com/common/discovery/keys'
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Header and Claim Checker Management

## Checker Manager Factory Services

The Symfony Bundle provides Header and Claim Checker Manager Factory services. These services are available when the `web-token/jwt-checker` component is installed:

```bash
composer require web-token/jwt-checker
```

```php
<?php

use Jose\Component\Checker\HeaderCheckerManagerFactory;
use Jose\Component\Checker\ClaimCheckerManagerFactory;

$headerCheckerManagerFactory = $container->get(HeaderCheckerManagerFactory::class);
$headerCheckerManager = $headerCheckerManagerFactory->create([...]);

$claimCheckerManagerFactory = $container->get(ClaimCheckerManagerFactory::class);
$claimCheckerManager = $claimCheckerManagerFactory->create([...]);
```

## Checker Manager Services

You can create Header and Claim Checker Managers using the bundle configuration.

```yaml
jose:
    checkers:
        claims:
            checker1:
                is_public: true
                claims: [...]
        headers:
            checker1:
                is_public: true
                headers: [...]
```

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.

## Custom Header Or Claim Checker

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`.

```yaml
services
    Acme\Checker\CustomHeaderChecker:
        public: false
        tags:
            - { name: 'jose.checker.header', alias: 'foo' }
    Acme\Checker\CustomClaimChecker:
        public: false
        tags:
            - { name: 'jose.checker.claim', alias: 'bar' }
```

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`.

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the header and claim checker managers.

```yaml
jose:
    checkers:
        claims:
            checker1:
                claims: [...]
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Signed Tokens

To use the signed tokens (JWS), you have to install the [`web-token/jwt-signature` component](https://github.com/web-token/jwt-signature).

```bash
composer require web-token/jwt-signature
```

When this component is installed, signature algorithms are automatically handles by the Algorithm Manager Factory.

* [JWS serializers](/1.x/symfony-bundle/signed-tokens/jws-serializers),
* [JWS creation](/1.x/symfony-bundle/signed-tokens/jws-creation),
* [JWS verification](/1.x/symfony-bundle/signed-tokens/jws-verification).


# JWS serializers

## JWS Serializer Manager Factory Service

A `JWSSerializerManagerFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSSerializerManagerFactory;

$jwsSerializerManagerFactory = $container->get(JWSSerializerManagerFactory::class);
```

With this factory, you will be able to create the JWSSerializerManager you need:

```php
$jwsSerializerManager = $jwsSerializerManagerFactory->create(['jws_compact']);
```

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`

## JWS Serializer Manager As Service

There is also another way to create a JWSSerializerManager object: using the bundle configuration.

```yaml
jose:
    jws:
        serializers:
            serializer1:
                serializers: ['jws_compact']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Serializer Manager service named `jose.jws_serializer.serializer1` with selected serialization modes.

```php
<?php
$jwsSerializerManager = $container->get('jose.jws_serializer.serializer1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        serializers:
            serializer1:
                serializers: ['jws_compact']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWS creation

## JWS Builder Factory Service

A `JWSBuilderFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSBuilderFactory;

$jwsBuilderFactory = $container->get(JWSBuilderFactory::class);
```

With this factory, you will be able to create the JWSBuilder you need:

```php
$jwsBuilder = $jwsBuilderFactory->create(['HS256']);
```

You can now use the JWSBuilder as explained in the JWS Creation section.

## JWS Builder As Service

There is also another way to create a JWSBuilder object: using the bundle configuration.

```yaml
jose:
    jws:
        builders:
            builder1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Builder service named `jose.jws_builder.builder1` with selected signature algorithms.

```php
<?php
$jwsBuilder = $container->get('jose.jws_builder.builder1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        builders:
            builder1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWS verification

## JWS Verifier Factory Service

A `JWSVerifierFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSVerifierFactory;

$jwsVerifierFactory = $container->get(JWSVerifierFactory::class);
```

With this factory, you will be able to create the JWSVerifier you need:

```php
$jwsVerifier = $jwsVerifierFactory->create(['HS256']);
```

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.**

## JWS Verifier As Service

There is also another way to create a JWSVerifier object: using the bundle configuration.

```yaml
jose:
    jws:
        verifiers:
            verifier1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Verifier service named `jose.jws_verifier.verifier1` with selected signature algorithms.

```php
<?php
$jwsVerifier = $container->get('jose.jws_verifier.verifier1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        verifiers:
            verifier1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

## JWS Loader Service

> This feature was introduced in version 1.1.

The [`JWSLoaderFactory`](/1.x/components/signed-tokens-jws/jws-loading) 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.

```php
<?php
use Jose\Component\Signature\JWSLoaderFactory;

$jwsLoaderFactory = $container->get(JWSLoaderFactory::class);
```

You can also create `JWSLoader` objects as services using the configuration of the bundle.

```yaml
jose:
    jws:
        loaders:
            jws_loader1:
                serializers: ['jws_compact']
                signature_algorithms: ['HS256']
                header_checkers: ['alg']
                is_public: true
```

Or using the [`ConfigurationHelper`](/1.x/symfony-bundle/configuration-helper).

```php
<?php
use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;

...
ConfigurationHelper::addJWSLoader($container, 'jws_loader1', ['jws_compact'], ['HS256'], ['alg'], true);
```


# Encrypted Tokens

To use the encrypted tokens (JWE), you have to install the [`web-token/jwt-encryption` component](https://github.com/web-token/jwt-encryption).

```bash
composer require web-token/jwt-encryption
```

When this component is installed, encryption algorithms are automatically handles by the Algorithm Manager Factory.

* [JWE serializers](/1.x/symfony-bundle/encrypted-tokens/jwe-serializers),
* [JWE creation](/1.x/symfony-bundle/encrypted-tokens/jwe-creation),
* [JWE decryption](/1.x/symfony-bundle/encrypted-tokens/jwe-decryption).


# JWE serializers

## JWE Serializer Manager Factory Service

A `JWESerializerManagerFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWESerializerManagerFactory;

$jweSerializerManagerFactory = $container->get(JWESerializerManagerFactory::class);
```

With this factory, you will be able to create the JWESerializerManager you need:

```php
$jweSerializerManager = $jweSerializerManagerFactory->create(['jwe_compact']);
```

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`

## JWE Serializer Manager As Service

There is also another way to create a JWESerializerManager object: using the bundle configuration.

```yaml
jose:
    jwe:
        serializers:
            serializer1:
                serializers: ['jwe_compact']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Serializer Manager service named `jose.jwe_serializer.serializer1` with selected serialization modes.

```php
<?php
$jweSerializerManager = $container->get('jose.jwe_serializer.serializer1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        serializers:
            serializer1:
                serializers: ['jwe_compact']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWE creation

## JWE Builder Factory Service

A `JWEBuilderFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWEBuilderFactory;

$jweBuilderFactory = $container->get(JWEBuilderFactory::class);
```

With this factory, you will be able to create the JWEBuilder you need:

```php
$jweBuilder = $jweBuilderFactory->create(
    ['A256GCMKW'],
    ['A256CBC-HS256'],
    ['DEF'] // Compression methods
);
```

Available compression methods are:

* `DEF`: deflate (recommended)
* `GZ`: gzip
* `ZLIB`: zlib

You can now use the JWEBuilder as explained in the JWE Creation section.

## JWE Builder As Service

There is also another way to create a JWEBuilder object: using the bundle configuration.

```yaml
jose:
    jwe:
        builders:
            builder1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Builder service named `jose.jwe_builder.builder1` with selected encryption algorithms.

```php
<?php
$jweBuilder = $container->get('jose.jwe_builder.builder1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        builders:
            builder1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWE decryption

## JWE Decrypter Factory Service

A `JWEDecrypterFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWEDecrypterFactory;

$jweDecrypterFactory = $container->get(JWEDecrypterFactory::class);
```

With this factory, you will be able to create the JWEDecrypter you need:

```php
$jweDecrypter = $jweDecrypterFactory->create(['HS256']);
```

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.**

## JWE Decrypter As Service

There is also another way to create a JWEDecrypter object: using the bundle configuration.

```yaml
jose:
    jwe:
        decrypters:
            decrypter1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Decrypter service named `jose.jwe_decrypter.decrypter1` with selected encryption algorithms.

```php
<?php
$jweDecrypter = $container->get('jose.jwe_decrypter.decrypter1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        decrypters:
            decrypter1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

## JWE Loader Service

> This feature was introduced in version 1.1.

The [`JWELoaderFactory`](/1.x/components/encrypted-tokens-jwe/jwe-loading) 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.

```php
<?php
use Jose\Component\Encryption\JWELoaderFactory;

$jweLoaderFactory = $container->get(JWELoaderFactory::class);
```

You can also create `JWELoader` objects as services using the configuration of the bundle.

```yaml
jose:
    jwe:
        loaders:
            jwe_loader1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                header_checkers: ['alg', 'enc']
                is_public: true
```

Or using the [`ConfigurationHelper`](/1.x/symfony-bundle/configuration-helper).

```php
<?php
use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;

...
ConfigurationHelper::addJWELoader($container, 'jwe_loader1', ['jwe_compact'], ['A256GCMKW'], ['A256CBC-HS256'], ['DEF'], ['alg', 'enc'], true);
```


# Configuration Helper

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`).

```php
<?php

declare(strict_types=1);

namespace AcmeBundle\DependencyInjection;

use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

final class AcmeExtension extends Extension implements PrependExtensionInterface
{
    ...

    /**
     * {@inheritdoc}
     */
    public function prepend(ContainerBuilder $container)
    {
        ... // The Helper will be called here
    }
}
```

Let say you want to create a JWK as a service:

```php
ConfigurationHelper::addKey(
    $container,
    'acme_my_key',
    'jwk', [
        'value' => '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}',
        'is_public' => true,
    ],
    [
        'tag_name1' => [],
        'tag_name2' => ['attribute1' => 'foo'],
    ]
);
```

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:

```yaml
jose:
    keys:
        acme_my_key:
            jwk:
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
                is_public: true
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

> 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](https://github.com/Spomky-Labs/lexik-jose-bridge/blob/v2.0/DependencyInjection/SpomkyLabsLexikJoseExtension.php#L78) to see how we configure the Jose Bundle without dedicated configuration


# Console

The project comes with console commands.\
They are available:

* [as a standalone command](/1.x/console/standalone)
* [through the dedicated Symfony console command](/1.x/console/symfony-console)
* [as a PHAR (PHP Archive)](/1.x/console/phar-application)

## Available Commands

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`.

### Key Management Commands

#### Private Key To Public Key Converter

This command will convert a private key into a public key. It has no effect on shared keys (e.g. `oct` keys).

```bash
./jose.phar key:convert:public '{"kty":"EC","crv":"P-256","d":"kiNCxSbRjlAbHrEbrwVKS8vIXUh6URChrmw","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}'

{"kty":"EC","crv":"P-256","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}
```

#### Key Analyze

The following command will analyze the key passed as argument and find issues.

```bash
./jose.phar key:analyze '{"kty":"oct","k":"N2aIJSQCxTo"}'

The parameter "alg" should be added.
The parameter "use" should be added.
The parameter "kid" should be added.
The key length is less than 128 bits.
```

#### PKCS#1 Key Converter

This command will convert a RSA or EC key into PKCS#1 key.

```bash
./jose.phar key:convert:pkcs1 '{"kty":"EC","crv":"P-256","d":"kiNCxSbRjlAbHrEbrwVKS8vIXUh6URChrmw","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}'

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJIjQsUm0Y5QGx6xG68N4GrprVrFSkvLyF1IelEQoa5soAoGCCqGSM49
AwEHoUQDQgAE+wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgmu3xcNNqUs
wJEHlO71ZBzZ3RM5XBdceRUNsjtwiKDqvg==
-----END EC PRIVATE KEY-----
```

#### Key Generators

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`.

```bash
./jose.phar key:generate:ec P-256

{"kty":"EC","crv":"P-256","d":"BZ231BFhhHAhx-D4myu4O1hi-vUHnRqxoCsQKUKFNrA","x":"Tv5YeQuD1CWDbfre65kYX2Lq_MGnUq0Ek2yUFixy31M","y":"pj0FyoGaByyBlt5RbTHhBdgcC-S6cgxzLpxd6mGmsbM"}
```

**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.

```bash
./jose.phar key:generate:rsa 512

{"kty":"RSA","n":"l1UPHqgOFThDUlfrP2DFnCwsD5ITls12nXer6A4YepUP_DnF9mFoXCkyflA_TOJtFiZW6NXWOY0NdE3YjzT-qQ","e":"AQAB","d":"CxVvxg8I-QTl6WIHGN09m_KgR4Ora6Agz-ez74sYv-GONPD3yjEWeAavdOsGK8iJX4Pe1Qss52VKddeKRQ9LAQ","p":"xkR0kbThGGD8HYtfPUv5Ds1zE5LlQvYgBiv15eOk9ns","q":"w2Xk86kiaRhXWXM8XPJ5Tn6bdTT6thzoqazuIO53SCs","dp":"RCBLibGEUvMoTiKQtChByRNRQl2MR2j48gXy9W42Rbc","dq":"T0x5910LxwUG5hl7ROluy6lcI9wFZ4Uh80JoPdspc5M","qi":"Z73ha9Fmg6s-rgRbF0dG0QMd1aY9g1i8qnAxXp3JMus"}
```

**Octet Key**

This command will generate a octet key (oct). Recommended size is 128 bits or more.

```bash
./jose.phar key:generate:oct 256

{"kty":"oct","k":"kWpZXidz3sVVx2Jn1J-5ANXnA2IKwfIAY2CoBW1q7I0"}
```

**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).

```bash
./jose.phar key:generate:okp 256

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**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.

```bash
./jose.phar key:generate:none

{"kty":"none","use":"sig","alg":"none"}
```

**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`).

```bash
./jose.phar key:generate:from_secret "This is my secret"
```

In case your secret is binary string, you will have to encode it first (Base64) and indicate it is encoded.

```bash
./jose.phar key:generate:from_secret "VGhpcyBpcyBteSBzZWNyZXQ=" --is_b64
```

#### Key Loaders

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.

```bash
./jose.phar key:load:key /path/to/file.pem "This is my secret to decrypt the key"

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**Convert From PKCS#12 Keys**

This command can load and convert a PKCS#12 key file into a JWK. It supports encrypted keys.

```bash
./jose.phar key:load:p12 /path/to/file.p12 "This is my secret to decrypt the key"

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**Convert From A X.509 Certificate**

This command can load and convert a X.509 key file into a JWK.

```bash
./jose.phar key:load:x509 /path/to/file.cert

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I"}
```

#### RSA Key Optimization

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`.

```bash
./jose.phar key:optimize '{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ"}'

{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ","p":"w0WuNlrO16rSPKHQn02FsOwzczlchC9ZpdS-00JKOr8","q":"xqn5LMfXwhWK-RGlXkSUHKCPb-SLKV8f8p41pDkjvvk","dp":"NGGAtfvt-FROSQ1vFQyKjEcQFhyRALRi6-UBu1HQ76k","dq":"kUqaO4_kUcNjogivwqOxFsauYIzq4dT6Dnx6iqJnbDE","qi":"TwJ4WOG0r1q6vZ13Kze2HPXtlnllyq9ZfClrVwovC_I"}
```

*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.*

#### Key Thumbprint

This command will calculate the key thumbprint as per the [RFC7638](https://tools.ietf.org/html/rfc7638). The following options are available:

* `-o` or `--out`: save the output into a file: `--out private.key`.
* `--hash`: the hashing method. Default is `sha256`. Supported methods are the one listed by [`hash_algos`](http://php.net/manual/en/function.hash-algos.php).

```bash
./jose.phar key:thumbprint '{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ","p":"xqn5LMfXwhWK-RGlXkSUHKCPb-SLKV8f8p41pDkjvvk","q":"w0WuNlrO16rSPKHQn02FsOwzczlchC9ZpdS-00JKOr8","dp":"kUqaO4_kUcNjogivwqOxFsauYIzq4dT6Dnx6iqJnbDE","dq":"NGGAtfvt-FROSQ1vFQyKjEcQFhyRALRi6-UBu1HQ76k","qi":"dkguRXkQcrvYbvFcnmGrcjIs36FJa-1dtd7QCRYHTBo"}'

gNur2UtA8NMAoxJfgMYhJqnuWR8u-60aeRbKtZwj4DE
```

### Keyset Management Commands

#### Private Keys To Public Keys Converter

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).

```bash
./jose.phar keyset:convert:public '<keyset here>'

<public keyset>
```

#### Key Analyze

This command has the same behaviour as `key:analyze` except that it will analize all keys in the keyset.

```bash
./jose.phar keyset:analyze '<keyset here>'

<keyset analyze result>
```

#### Keyset Generators

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:

```bash
./jose.phar keyset:generate:rsa 3 512 # Create 3 RSA keys (512 bits each)
./jose.phar keyset:generate:oct 5 128 # Create 5 oct keys (128 bits each)
./jose.phar keyset:generate:okp 2 X25519 # Create 2 OKP keys (curve X25519)
./jose.phar keyset:generate:ec 3 P-521 # Create 3 EC keys (curve P-521)
```

The result of these commands is a JWKSet object.

#### Key Set Modification

* `keyset:add:key`:         Add a key into a key set.
* `keyset:merge`:           Merge several key sets into one.
* `keyset:rotate`:          Rotate a key set.

#### Distant Key Set Loading

* `keyset:load:jku`:        Loads a key set from an url.
* `keyset:load:x5u`:        Loads a key set from an url.


# Standalone Application

## Installation

To install the standalone application, you have to clone the repository and install the dependencies.\
We consider that `git` and `composer` are correctly installed.

```bash
git clone https://github.com/web-token/jwt-app.git
cd jwt-app
composer install --no-dev --optimize-autoloader --classmap-authoritative
```

You will find the standalone console command in the `bin` folder.

```bash
./bin/jose
```


# Symfony Console

To enable the commands on a Symfony application, you have to install and add the associated bundle into your kernel:

```bash
composer require web-token/jwt-console
composer require web-token/jwt-bundle
```

If you use Symfony Flex, you have nothing to do. Otherwise you have to enable to bundle.

```php
// app/AppKernel.php

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            ...
            new Jose\Bundle\JwtFramework\JwtFrameworkBundle(),
        ];

        return $bundles;
    }
    ...
}
```

Then execute your Symfony Console command to use the command provided by this component:

```bash
./bin/console
```


# PHAR Application

## Installation

To install the application, you just have to download it and download the associated public key (the application is digitally signed):

```bash
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
```

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:

```bash
./jose.phar
```

## Update

The application can be updated easily:

```bash
./jose.phar selfupdate
```

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:

```bash
./jose.phar rollback
```


# Security Recommendations

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.

## Algorithms

### Algorithm Choice

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.

### Available 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.

### Avoid Weak Algorithms

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.

## Keys And Key Sets

### Key Size

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.

### Additional Information

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).&#x20;
* `alg`: the algorithm allowed to be used with this key.

### Key Rotation

A key is fine but may be cracked e.g. by bruteforce. Changing you keys after several days or weeks is encouraged.

## Token Creation

### Header Parameters

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.

### Payload And Claims

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.

#### Token Unique ID

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.

#### Time Indicators

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.

#### Issuer And Audience

The claims `iss` (issuer) and `aud` (audience) should always be set. When duplicated in the header, their values MUST be identical.

## Application Communication

### Secured Connection

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.

## Loading Process

When you receive a token, the following steps should be followed in this order. If one failed, you you reject the whole token.

1. Unserialize the token
2. For each signature/recipient (may be possible when using the Json General Serialization Mode):
   1. Check the complete header (protected and unprotected)
   2. Verify the signature (JWS) or decrypt the token (JWE)
   3. Check the claims in the payload (if any)

### Unserialize The Token

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.

### Check The Header

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.

### Signature Verification / Payload Decryption

Let the component do its job. The most important step for developers is to ensure that the right key/ket set is used.

### Check The Claims

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.

## Stay Tuned

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 [Security group on Stack Exchange](https://security.stackexchange.com/) is a good start.


# Advanced Topics

* [Serialization](/1.x/advanced-topics/serialization)
* [Nested Tokens](/1.x/advanced-topics/nested-tokens)
* [Custom Algorithm](/1.x/advanced-topics/custom-algorithm)
* Signed tokens and
  * [Unprotected Header](/1.x/advanced-topics/signed-tokens-and/unprotected-header)
  * [Multiple Signatures](/1.x/advanced-topics/signed-tokens-and/multiple-signatures)
  * [Detached Payload](/1.x/advanced-topics/signed-tokens-and/detached-payload)
  * [Unencoded Payload](/1.x/advanced-topics/signed-tokens-and/unencoded-payload)
* Encrypted tokens and
  * [Unprotected Header](/1.x/advanced-topics/encrypted-tokens-and/unprotected-headers)
  * [Multiple Recipients](/1.x/advanced-topics/encrypted-tokens-and/multiple-recipients)
  * [Additional Authentication Data (AAD)](/1.x/advanced-topics/encrypted-tokens-and/additional-authentication-data-aad)


# Nested Tokens

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`

## Nested Token Loading

To instantiate the `NestedTokenLoader`, you need a `JWSLoader` and a `JWELoader`.

```php
use Jose\Component\Encryption\NestedTokenLoader;

$nestedTokenLoader = new NestedTokenLoader($jweLoader, $jwsLoader);
```

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.

```php
$jws = $nestedTokenLoader->load($token, $encryptionKeySet, $signatureKeySet, $signature);
```

## Nested Token Building

To instantiate the `NestedTokenBuilderder`, you will need the following components:

* a `JWSBuilder`,
* a `JWEBuilder`,&#x20;
* a `JWESerializerManager`,
* a `JWSSerializerManager`

```php
use Jose\Component\Encryption\NestedTokenBuilder;

$nestedTokenBuilder = new NestedTokenBuilder($jweLoader, $jweSerializerManager, $jwsLoader, $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.

```php
$token = $builder->create(
    $payload,                                     // The payload to protect
    [[                                            // A list of signatures. 'key' is mandatory and at least one of 'protected_header'/'header' has to be set.
        'key'              => $signature_key,     // The key used to sign. Mandatory.
        'protected_header' => ['alg' => 'PS256'], // The protected header. Optional.
        'header'           => ['foo' => 'bar'],   // The unprotected header. Optional.
    ]],
    'jws_json_flattened',                         // The serialization mode for the JWS
    ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'],    // The shared protected header. Optional.
    ['foo' => 'bar'],                             // The shared unprotected header. Optional.
    [[                                            // A list of recipients. 'key' is mandatory.
        'key'    => $encryption_key,              // The recipient key.
        'header' => ['bar' => 'foo'],             // The recipient unprotected header.
    ]],
    'jwe_json_flattened'                          // The serialization mode for the JWE.
    '1, 2, 3, 4'                                  // Additional Authenticated Data (AAD). Optional.
);
```

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.

## Symfony Bundle

### Configuration

Hereafter an example of a Symfony application configuration:

```yaml
jose:
    nested_token:
        loaders:
            loader_1:
                signature_algorithms: ['PS256']
                key_encryption_algorithms: ['RSA-OAEP']
                content_encryption_algorithms: ['A128GCM']
                jws_serializers: ['jws_compact']
                jws_header_checkers: [...]
                jwe_serializers: ['jwe_compact']
                jwe_header_checkers: [...]
                is_public: true
        builders:
            builder_1:
                signature_algorithms: ['PS256']
                key_encryption_algorithms: ['RSA-OAEP']
                content_encryption_algorithms: ['A128GCM']
                jws_serializers: ['jws_compact']
                jwe_serializers: ['jwe_compact']
                is_public: true
```

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.

### Configuration Helper

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.

```php
class AcmeExtension extends Extension implements PrependExtensionInterface
{
    ...

    public function prepend(ContainerBuilder $container)
    {
        ConfigurationHelper::addNestedTokenLoader($container, 'loader_1', ['jwe_compact'], ['RSA-OAEP'], ['A128GCM'], ['DEF'], [], ['jws_compact'], ['PS256'], [], true, []);
        ConfigurationHelper::addNestedTokenBuilder($container, 'builder_1', ['jwe_compact'], ['RSA-OAEP'], ['A128GCM'], ['DEF'], ['jws_compact'], ['PS256'], true, []);
    }
}
```


# Serialization

The [RFC7515](https://tools.ietf.org/html/rfc7515) (JWS) and [RFC7516](https://tools.ietf.org/html/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.

## JWS Serialization

To use the JWS serializers, you have to install the `jwt-signature` component.

```bash
composer require web-token/jwt-signature
```

### JWS Compact

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:

```
eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA.AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn
```

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

### JWS JSON Flattened

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:

```javascript
{
  "payload": "SW4gb3VyIHZpbGxhZ2UsIGZvbGtzIHNheSBHb2QgY3J1bWJsZXMgdXAgdGhlIG9sZCBtb29uIGludG8gc3RhcnMu",
  "protected": "eyJhbGciOiJFUzI1NiJ9",
  "header": {
    "kid": "myEcKey"
  },
  "signature": "b7V2UpDPytr-kMnM_YjiQ3E0J2ucOI9LYA7mt57vccrK1rb84j9areqgQcJwOA00aWGoz4hf6sMTBfobdcJEGg"
}
```

### JWS JSON General

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:

```javascript
{
  "payload": "SW4gb3VyIHZpbGxhZ2UsIGZvbGtzIHNheSBHb2QgY3J1bWJsZXMgdXAgdGhlIG9sZCBtb29uIGludG8gc3RhcnMu",
  "signatures": [
    {
      "protected": "eyJhbGciOiJSUzI1NiJ9",
      "header": {
        "kid": "myRsaKey"
      },
      "signature": "B04c24gSnpVm1Z-_bemfyNMCpZm6Knj1yB-yzaIOvijsWfDgoF_mSJccTIbzapNgwJudnobr5iDOfZWiRR9iqCyDJLe5M1S40vFF7MFEI3JecYRgrRc6n1lTkYLMRyVq48BwbQlmKgPqmK9drun3agklsr0FmgNx65pfmcnlYdXsgwxf8WbgppefrlrMImp-98-dNtBcUL8ce1aOjbcyVFjGMCzpm3JerQqIzWQvEwBstnMEQle73KHcyx_nsTmlzY70CaydbRTsciOATL7WfiMwuX1q9Y2NIpTg3CbOTWKdwjh7iyfiAKQxNBaF2mApnqj9hjpf8GwR-CfxAzJtPg"
    },
    {
      "protected": "eyJhbGciOiJFUzI1NiJ9",
      "header": {
        "kid": "myEcKey"
      },
      "signature": "2cbugKq0ERaQMh01n2B-86EZFYleeMf8bsccaQMxzOxAg14PxfjR3IImvodTJYqkmfBJYW203etz2-7ZtJUOGw"
    },
    {
      "protected": "eyJhbGciOiJIUzI1NiJ9",
      "header": {
        "kid": "myMacKey"
      },
      "signature": "e7R9gjx0RsUNa3c7qd8k9mQGEhtcG8vsN1W7jbLb2MA"
    }
  ]
}
```

### JWS Serializer Manager

The serializer manager can be helpful when your application deals more than one serialization mode.

```php
<?php

require_once 'vendor/autoload.php';

use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Signature\Serializer;

$jsonConverter = new StandardConverter();

$manager = Serializer\JWSSerializerManager::create([
    new Serializer\CompactSerializer($jsonConverter),
    new Serializer\JSONFlattenedSerializer($jsonConverter),
    new Serializer\JSONGeneralSerializer($jsonConverter),
]);

// Serializes the second signature (index = 1) of the variable $jws (JWS object) into JSON Flattened serialization mode.
$token = $manager->serialize('jws_json_flattened', $jws, 1);

// Retrieve the JWS object from a token
$jws = $manager->unserialize($token);
```

## JWE Serialization

To use the JWE serializers, you have to install the `jwt-encryption` component.

### JWE Compact

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:

```
eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw
```

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.

### JWE JSON Flattened

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:

```javascript
{
  "protected":"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
  "unprotected":{"jku":"https://server.example.com/keys.jwks"},
  "header":{"alg":"A128KW","kid":"7"},
  "encrypted_key":"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ",
  "iv":"AxY8DCtDaGlsbGljb3RoZQ",
  "ciphertext":"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
  "tag":"Mz-VPPyU4RlcuYv1IwIvzw"
}
```

### JWE JSON General

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:

```javascript
 {
  "protected":"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
  "unprotected":{"jku":"https://server.example.com/keys.jwks"},
  "recipients":[
    {
      "header":{"alg":"RSA1_5","kid":"2011-04-29"},
      "encrypted_key":"UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A"
    },
    {
      "header":{"alg":"A128KW","kid":"7"},
      "encrypted_key":"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ"
    }
  ],
  "iv":"AxY8DCtDaGlsbGljb3RoZQ",
  "ciphertext":"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
  "tag":"Mz-VPPyU4RlcuYv1IwIvzw"
 }
```

### JWE Serializer Manager

The serializer manager can be helpful when your application deals more than one serialization mode.

```php
<?php

require_once 'vendor/autoload.php';

use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Encryption\Serializer;

$jsonConverter = new StandardConverter();

$manager = Serializer\JWESerializerManager::create([
    new Serializer\CompactSerializer($jsonConverter),
    new Serializer\JSONFlattenedSerializer($jsonConverter),
    new Serializer\JSONGeneralSerializer($jsonConverter),
]);

// Serializes the second recipient (index = 1) of the variable $jwe (JWE object) into JSON Flattened serialization mode.
$token = $manager->serialize('jwe_json_flattened', $jwe, 1);

// Retrieve the JWE object from a token
$jwe = $manager->unserialize($token);
```


# Custom Algorithm

This framework provides dozens of signature or encryption algorithms. If your application uses a custom algorithm or if another algorithm has been recently approved in the JWT context, it may be interesting to use it with this framework.

Hopefully, this is very easy. In the following example, we will create a class to use the ChaCha20 + Poly 1305 (IETF variant) encryption algorithm as a Key Encryption Algorithm.

```php
<?php

declare(strict_types=1);

namespace Acme\Algorithm;

use Base64Url\Base64Url;
use Jose\Component\Core\JWK;
use const Sodium\CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES;

/**
 * This algorithm is a custom algorithm that use the ChaCha20 + Poly 1305 with a 192 bits nonce (IETF variant).
 */
final class ChaCha20Poly1305IETF implements KeyEncryption //The algorithm acts as a Key Encryption algorithm
{
    /**
     * {@inheritdoc}
     */
    public function name(): string
    {
        return 'ChaCha20+Poly1305+IETF'; // The name of our algorithm. This name will be used in our JWE headers
    }

    /**
     * {@inheritdoc}
     */
    public function allowedKeyTypes(): array
    {
        return ['oct']; // Key types for this algorithm are octet keys
    }

    /**
     * {@inheritdoc}
     */
    public function encryptKey(JWK $key, string $cek, array $completeHeader, array &$additionalHeader): string
    {
        $this->checkKey($key); // We check the key
        $kek = Base64Url::decode($key->get('k')); // We retrieve the secret
        $nonce = random_bytes(CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES); // We create a nonce
        $additionalHeader['nonce'] = Base64Url::encode($nonce); // We add the nonce to the header

        return sodium_crypto_aead_chacha20poly1305_ietf_encrypt($cek, '', $nonce, $kek); // We return the encrypted CEK
    }

    /**
     * {@inheritdoc}
     */
    public function decryptKey(JWK $key, string $encrypted_cek, array $header): string
    {
        $this->checkKey($key); // We check the key
        $this->checkAdditionalParameters($header); // We verify the nonce is in the headers
        $nonce = Base64Url::decode($header['nonce']); // We retrieve the nonce
        $kek = Base64Url::decode($key->get('k')); // an the secret

        $decrypted = sodium_crypto_aead_chacha20poly1305_ietf_decrypt($encrypted_cek, '', $nonce, $kek); // We try to decrypt the CEK
        if (false === $decrypted) { // If it fails we throw an exception
            throw new \RuntimeException('Unable to decrypt.');
        }

        return $decrypted; // Otherwise we return the decrypted CEK
    }

    /**
     * @param JWK $key
     */
    protected function checkKey(JWK $key)
    {
        if (!in_array($key->get('kty'), $this->allowedKeyTypes())) {
            throw new \InvalidArgumentException('Wrong key type.');
        }
        if (!$key->has('k')) {
            throw new \InvalidArgumentException('The key parameter "k" is missing.');
        }
    }

    /**
     * @param array $header
     */
    protected function checkAdditionalParameters(array $header)
    {
        foreach (['nonce'] as $k) {
            if (!array_key_exists($k, $header)) {
                throw new \InvalidArgumentException(sprintf('Parameter "%s" is missing.', $k));
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getKeyManagementMode(): string
    {
        return self::MODE_ENCRYPT; //Key Management Mode is 'enc'.
    }
}
```


# Signed tokens and


# Unprotected Header

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](https://tools.ietf.org/html/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:

```php
$jws = $jwsBuilder
    ->create()
    ->withPayload('...')
    ->addSignature($jwk, ['alg' => 'HS256'], ['description' => 'Small description here', 'author' => 'John Doe'])
    ->build();
```

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.**


# Multiple Signatures

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):

```php
$jws = $jwsBuilder
    ->create()
    ->withPayload('...')
    ->addSignature($signature_key1, ['alg' => 'HS256'])
    ->addSignature($signature_key2, ['alg' => 'RS384'])
    ->addSignature($signature_key3, ['alg' => 'ES512'])
    ->build();
```

The variable `$jws` will be a valid JWS object with all computed signatures. Next step is the serialization of these signatures.

```php
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Signature\Serializer;

// The JSON Converter.
$jsonConverter = new StandardConverter();

$manager = Serializer\JWSSerializerManager::create([
    new Serializer\CompactSerializer($jsonConverter),
    new Serializer\JsonFlattenedSerializer($jsonConverter),
    new Serializer\JsonGeneralSerializer($jsonConverter),
]);

$tokenWithAllSignatures = $manager->serialize('jws_json_general', $jws);
$compactTokenWithSignatureAtIndex1 = $manager->serialize('jws_compact', $jws, 1);
$flattenedTokenWithSignatureAtIndex2 = $manager->serialize('jws_json_flattened', $jws, 2);
```


# Detached Payload

As per the [RFC7519](https://tools.ietf.org/html/rfc7515#appendix-F),the payload of a JWS may be detached. This framework supports this feature.

## JWS Creation

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](/1.x/components/signed-tokens-jws/jws-creation). There is only one argument that will change during the call of `withPayload`.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = AlgorithmManager::create([
    new HS256(),
]);

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// We instantiate our JWS Builder.
$jwsBuilder = new JWSBuilder(
    $jsonConverter,
    $algorithmManager
);

// The payload we want to sign
$payload = $jsonConverter->encode([
    'iat' => time(),
    'nbf' => time(),
    'exp' => time() + 3600,
    'iss' => 'My service',
    'aud' => 'Your application',
]);

$jws = $jwsBuilder
    ->create()                               // We want to create a new JWS
    ->withPayload($payload, true)            // /!\ Here is the change! We set the payload and we indicate it is detached
    ->addSignature($jwk, ['alg' => 'HS256']) // We add a signature with a simple protected header
    ->build();
```

And voilà! When you will serialize this token, the payload will not be present.

## JWS Loading

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.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\Serializer\CompactSerializer;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = AlgorithmManager::create([
    new HS256(),
]);

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The JSON Converter.
$jsonConverter = new StandardConverter();

// The serializer manager. We only use the JWS Compact Serialization Mode.
$serializerManager = JWSSerializerManager::create([
    new CompactSerializer($jsonConverter),
]);

// We instantiate our JWS Verifier.
$jwsVerifier = new JWSVerifier(
    $algorithmManager
);

// The detached payload
$payload = '{"iat":1507896992,"nbf":1507896992,"exp":1507900592,"iss":"My service","aud":"Your application"}';

// The input we want to check
$token = 'eyJhbGciOiJIUzI1NiJ9..eycp9PTdgO4WA-68-AMoHPwsKDr68NhjIQKz4lUkiI0';

// We try to load the token.
$jws = $serializerManager->unserialize($token);

// We verify the signature.
// /!\ The third argument is the detached payload.
$jwsVerifier->verifyWithKey($jws, $jwk, $payload);
```


# Unencoded Payload

The [RFC7797](https://tools.ietf.org/html/rfc7797) 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:

```php
$jws = $jwsBuilder
    ->create()
    ->withPayload('Hello World!')
    ->addSignature($jwk, ['alg' => 'HS256', 'b64' => false, 'crit' => ['b64']])
    ->build();
```

*As a remainder, both* `b64` *and* `crit` *parameters MUST be in the protected header.*


# Encrypted tokens and


# Unprotected Headers

As well as the [signed tokens](/1.x/advanced-topics/signed-tokens-and/unprotected-header), 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:

```php
$jwe = $jweBuilder
    ->create()
    ->withPayload('...')
    ->withSharedProtectedHeader(['enc' => 'A256GCM', 'alg' => 'A256KW'])
    ->withSharedHeader(['author' => 'John Doe'])
    ->addRecipient($recipient_public_key_1, ['message' => 'Hello World!'])
    ->addRecipient($recipient_public_key_2, ['description' => 'Nice song for you'])
    ->build();
```

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.**


# Multiple Recipients

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).

```php
$jweBuilder
    ->create()
    ->withPayload('...')
    ->withSharedProtectedHeader(['enc' => 'A128GCM'])
    ->addRecipient($recipient_key_1, ['alg' => 'RSA1_5'])
    ->addRecipient($recipient_key_2, ['alg' => 'RSA-OAEP-256'])
    ->build();
```

**Note: when an unprotected header is set, the Compact Serialization mode is not available.**

## Key Management Modes

Each Key Encryption Algorithm has its own Key Management Mode.

### Key Encryption Algorithms And Associated Key Management Mode.

| 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            |                      |                                 |                   |

### Compatibility table between Key Management Modes:

| 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                |


# Additional Authentication Data (AAD)

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:

```php
$jwe = $jweBuilder
    ->create()
    ->withPayload('...')
    ->withSharedProtectedHeader([
        'enc' => 'A256CBC-HS512',
        'alg' => 'RSA-OAEP-256',
        'zip' => 'DEF',
    ])
    ->addRecipient($recipient_key)
    ->withAAD('A,B,C,D')
    ->build();
```

**Note: when the AAD is set, the Compact Serialization mode is not available.**


# Benchmarks

You can easily check if an algorithm is fast enough on your platform. This project has tests for all operations with (almost) all algorithms.

## All algorithms

To run those tests, you must install the library with all dev dependencies. When done, just run the following command:

```bash
./vendor/bin/phpbench run --store
```

**The previous command will test ALL algorithms and may take more than 7 hours.**

## Algorithm Selection

We recommend you to run tests only for the algorithm(s) you want to use. Just run the following command:

```bash
./vendor/bin/phpbench run --group GROUP --store
```

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`

## Examples

Test all HMAC algorithms:

```bash
./vendor/bin/phpbench run --group hmac --store
```

Test the RSA1\_5 algorithm:

```bash
./vendor/bin/phpbench run --group RSA1_5 --store
```

## Benchmark Details

The result of the following command will only give you partial result. For example:

```bash
PhpBench 0.13.0. Running benchmarks.
Using configuration file: phpbench.json

............

12 subjects, 12 iterations, 12,000 revs, 0 rejects
(best [mean mode] worst) = 31.275 [86.783 86.783] 31.275 (μs)
⅀T: 1,041.395μs μSD/r 0.000μs μRSD/r: 0.000%
Storing results ... OK
Run: 133c8a853cf321f0b7b63e4e60f819f9910e1285
```

The main information is that the best algorithm takes only 31.275 µs... but you may need more information.

Just run the following command:

```bash
./vendor/bin/phpbench report --report=simple --output=md --uuid=133c8a853cf321f0b7b63e4e60f819f9910e1285
```

\*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:

```
Jose Performance Test Suite
===========================

### suite: 133c8a853cf321f0b7b63e4e60f819f9910e1285, date: 2017-09-20, stime: 22:05:45

benchmark | groups | subject | mean
 --- | --- | --- | --- 
HS256Bench | JWS,hmac,HS256 | benchSignature | 104.450μs
HS256Bench | JWS,hmac,HS256 | benchVerification | 161.093μs
HS384Bench | JWS,hmac,HS384 | benchSignature | 112.788μs
HS384Bench | JWS,hmac,HS384 | benchVerification | 161.978μs
HS512Bench | JWS,hmac,HS512 | benchSignature | 105.686μs
HS512Bench | JWS,hmac,HS512 | benchVerification | 163.139μs
```

If it is not enough for you, you can get a full report with the following command:

```bash
./vendor/bin/phpbench report --report=default --output=md --uuid=133c8a853cf321f0b7b63e4e60f819f9910e1285
```


# Result table

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 <https://en.wikipedia.org/wiki/PBKDF2>). Default salt size (512 bits) and iterations (4096) and custom values (256/1024) used for the tests. Those values can be configured if needed.

| 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)                                                                 |


# Migration

The following pages will help you to migrate your application to this project.

* [From spomky-labs/jose](/1.x/migration/from-spomky-labs-jose)


# From spomky-labs/jose

The following pages will help you to migrate from [spomky-labs/jose](https://github.com/Spomky-Labs/jose) and [spomky-labs/jose-bundle](https://github.com/Spomky-Labs/jose-bundle) to that new framework.

* [Keys (JWK)](/1.x/migration/from-spomky-labs-jose/keys-jwk)
* [Key Sets (JWKSet)](/1.x/migration/from-spomky-labs-jose/key-sets-jwkset)
* [Signed Tokens (JWS)](/1.x/migration/from-spomky-labs-jose/signed-tokens-jws)
* [Encrypted Tokens (JWE)](/1.x/migration/from-spomky-labs-jose/encrypted-tokens-jwe)
* [Header Checking](/1.x/migration/from-spomky-labs-jose/header-checking)
* [Claim Checking](/1.x/migration/from-spomky-labs-jose/claim-checking)


# Keys (JWK)

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**

```php
<?php

use Jose\Object\JWK;

$key = new JWK([
    'kty' => 'RSA',
    'n' => '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw',
    'e' => 'AQAB',
    'alg' => 'RS256',
    'kid' => '2011-04-29',
]);

$key->has('kty'); // true
$key->get('kty'); // RSA
$key->thumbprint('sha256'); // The Sha-256 thumbprint of the key: "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
json_encode($key); // The key as a Json object: "{"kty":"RSA","n":"0vx7agoebGcQSuuPiLJXZptN9n...8awapJzKnqDKgw","e":"AQAB","alg":"RS256","kid":"2011-04-29"}"
$key->toPublic(); // Converts a private key to a public one (not relevant in this example as the key is public)
$key->getAll(); // All key parameters
```

**After**

```php
<?php

use Jose\Component\Core\JWK;

$key = new JWK([
    'kty' => 'RSA',
    'n' => '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw',
    'e' => 'AQAB',
    'alg' => 'RS256',
    'kid' => '2011-04-29',
]);

$key->has('kty'); // Unchanged
$key->get('kty'); // Unchanged
$key->thumbprint('sha256'); // Unchanged
json_encode($key); // Unchanged
$key->toPublic(); // Unchanged
$key->all(); // The method name changed.
```


# Key Sets (JWKSet)

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**

```php
<?php

use Jose\Object\JWKSet;

$keyset = new JWKSet(['keys' => [
    '71ee230371d19630bc17fb90ccf20ae632ad8cf8' => [
        'kid' => '71ee230371d19630bc17fb90ccf20ae632ad8cf8',
        'kty' => 'RSA',
        'alg' => 'RS256',
        'use' => 'sig',
        'n' => 'vnMTRCMvsS04M1yaKR112aB8RxOkWHFixZO68wCRlVLxK4ugckXVD_Ebcq-kms1T2XpoWntVfBuX40r2GvcD9UsTFt_MZlgd1xyGwGV6U_tfQUll5mKxCPjr60h83LXKJ_zmLXIqkV8tAoIg78a5VRWoms_0Bn09DKT3-RBWFjk=',
        'e' => 'AQAB',
]]]);

json_encode($keyset); // The key as a Json object
$keyset->addKey(new JWK(['kty' => 'none'])); // Add a key
$keyset->removeKey(1); // Remove a key
$keyset->prependKey(new JWK(['kty' => 'none'])); // Prepend a key
$keyset[0]; // Access keys like arrays do
foreach ($keyset as $key) { // Iterate on a key set
    ...
}
```

**After**

```php
<?php

use Jose\Component\Core\JWKSet;

// Create using direct values
$keyset = JWKSet::createFromKeyData(['keys' => [
    '71ee230371d19630bc17fb90ccf20ae632ad8cf8' => [
        'kid' => '71ee230371d19630bc17fb90ccf20ae632ad8cf8',
        'kty' => 'RSA',
        'alg' => 'RS256',
        'use' => 'sig',
        'n' => 'vnMTRCMvsS04M1yaKR112aB8RxOkWHFixZO68wCRlVLxK4ugckXVD_Ebcq-kms1T2XpoWntVfBuX40r2GvcD9UsTFt_MZlgd1xyGwGV6U_tfQUll5mKxCPjr60h83LXKJ_zmLXIqkV8tAoIg78a5VRWoms_0Bn09DKT3-RBWFjk=',
        'e' => 'AQAB',
]]]);

// Create using a list of JWK objects
$keyset = JWKSet::createFromKeys([
    JWK::create(['kty' => 'none']),
]);

// Create from a JWKSet as a Json object
$keyset = JWKSet::createFromJson('{"keys":{"71ee230371d19630bc17fb90ccf20ae632ad8cf8":{"kid":"71ee230371d19630bc17fb90ccf20ae632ad8cf8","kty":"RSA","alg":"RS256","use":"sig","n":"vnMTRCMvsS04M1yaKR112aB8RxOkW...9DKT3-RBWFjk=","e":"AQAB"}}}');
$keyset->has('71ee230371d19630bc17fb90ccf20ae632ad8cf8'); // Indicates if a key with a key ID (string) or index (integer) is in the key set.
$keyset->get('71ee230371d19630bc17fb90ccf20ae632ad8cf8'); // Retrieve a key with a key ID (string) or index (integer).
$keyset->count(); // Number of keys in the key set.
count($keyset); // Number of keys in the key set.
$keyset->all(); // An array of keys.
$newKeyset = $keyset->with(JWK::create(['kty' => 'none'])); // Adds a key in the key set. The returned key set is a new object (immutability).
$newKeyset = $keyset->without(0); // Removes a key from the key set. The returned key set is a new object (immutability).
$keyset->selectKey('sig', new RS256(), ['kid' => '71ee230371d19630bc17fb90ccf20ae632ad8cf8']);
```

*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`.

### Removed Classes

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](/1.x/console)),
* using the `JWKFactory` or `JKUFactory`,
* using a custom key manager.

## Keys/Key Sets And The Symfony Bundle

### Env Var Processor

If you use Symfony 3.4+, you will be able to load a keys and key sets using an environment variable and process it:

```yaml
parameters:
    private_key_set: '%env(jwkset:PRIVATE_KEY_SET)'
    signature_key: '%env(jwk:SIGNATURE_KEY)'
```

It the environment variables are valid keys and key sets, the associated parameters will converted as a `JWK` or a `JWKSet` object.

```php
$container->getParameter('private_key_set'); // Will return a JWKSet object
```

These parameters can be injected a usual:

```php
<?php

declare(strict_types=1);

namespace AppBundle\Service;

use Jose\Component\Core\JWKSet;

final class Foo
{
    public function __construct(JWKSet $jwkset)
    {
        ...
    }
}
```

Associated service configuration:

```yaml
services:
    AppBundle\Service\Foo:
        arguments:
            - '%private_key_set%'
```

**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.**

### JKUFactory / X5UFactory

**Before**

```php
<?php

use Jose\Factory\JWKFactory;

$jwkset = JWKFactory::createFromJKU('https://www.googleapis.com/oauth2/v3/certs');
```

**After**

The use of this feature is drastically different. JKUFactory and X5UFactory are now services that relies on [HttPlug](http://docs.php-http.org/en/latest/) 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](http://docs.php-http.org/en/latest/clients.html#clients-adapters) (I will use `php-http/guzzle6-adapter` here)

Do not forget to enable the associated bundles:

```php
new Http\HttplugBundle\HttplugBundle(),
new Jose\Bundle\JoseFramework\JoseFrameworkBundle(),
```

* Create a request factory service

```php
<?php
# app/AppBundle/Service/RequestFactory.php

namespace AppBundle\Service;

use GuzzleHttp\Psr7\Request;
use Http\Message\RequestFactory as Psr7RequestFactory;

final class RequestFactory implements Psr7RequestFactory
{
    /**
     * {@inheritdoc}
     */
    public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1')
    {
        return new Request($method, $uri, $headers, $body, $protocolVersion);
    }
}
```

```yaml
services:
    AppBundle\Service\RequestFactory: ~
```

* Configure the bundles:

```yaml
jose:
    jku_factory:
        enabled: true # We enable the JKU factory
        client: 'httplug.client.my_client' # We indicate the Httplug client to use
        request_factory: 'AppBundle\Service\RequestFactory' # See hereafter the corresponding class

httplug:
    plugins:
        cache: # We use the cache plugin
            cache_pool: 'cache.app' # We use the PSR-6 Cache service of the application
            config:
                default_ttl: 1800 # TTL set to 30 min
    clients:
        my_client: # Our client based on Guzzle 6. The corresponding service will be `httplug.client.my_client`
            factory: 'httplug.factory.guzzle6'
            plugins: ['httplug.plugin.cache'] # We enable the cache plugin for that client
```

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:

```php
use Jose\Component\Core\JWKSet;
use Jose\Component\KeyManagement\JKUFactory;

class MyClass
{
    private $jkuFactory;

    public function __construct(JKUFactory $jkuFactory)
    {
        $this->client = $client;
        $this->jkuFactory= $jkuFactory;
    }

    public function getKeySet(): JWKSet
    {
        return $this->jkuFactory->loadFromUrl($url);
    }
}
```

* Configure a key set in the bundle configuration

```yaml
jose:
    keys:
        microsoft_keys:
            jku:
                url: 'https://login.microsoftonline.com/common/discovery/keys'
```

The associated service will be `jose.key_set.microsoft_keys`.


# Signed Tokens (JWS)

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`).

## Signed Tokens Creation

**Before**

```php
<?php

use Jose\Factory\JWKFactory;
use Jose\Factory\JWSFactory;

$header = [
  'alg' => 'RS256',
];

$jws = JWSFactory::createJWSToCompactJSON(
    $claims, // The payload
    $key,    // The private/shared key used to sign
    $header  // The token protected header
);
```

**After**

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Algorithm\RS256;
use Jose\Component\Signature\Serializer\CompactSerializer;

// This converter wraps json_encode/json_decode with some parameters
$jsonConverter = new StandardConverter();

// This managers handles all algorithms we need to use. 
$algorithmManager = AlgorithmManager::create([
    new RS256(),
]);

// The JWS Builder
$jwsBuilder = new JWSBuilder($jsonConverter, $algorithmManager);

// First we have to encode the payload. Now only strings are accepted.
$payload = $jsonConverter->encode($claims);

// We build our JWS object
$jws = $jwsBuilder
    ->create()                    // Indicates we want to create a new token
    ->withPayload($payload)       // We set the payload
    ->addSignature($key, $header) // We add a signature
    ->build();                    // We compute the JWS

// We need to serialize the token.
// In this example we will use the compact serialization mode (most common mode).
$serializer = new CompactSerializer($jsonConverter);
$token = $serializer->serialize($jws);
```

## Signed Tokens Loading

**Before**

```php
<?php

use Jose\Checker\AudienceChecker;
use Jose\Factory\CheckerManagerFactory;
use Jose\Loader;

// The loader
$loader = new Loader();

// We load and verify the input
$jws = $loader->loadAndVerifySignatureUsingKey(
    $input,
    $key,
    ['RS256'],
    $signature_index
);

// We prepare the claim/header checker
$checker = CheckerManagerFactory::createClaimCheckerManager(
    ['iat', 'nbf'], // We should enable 'exp', but this example will fail as the token has already expired
    ['crit']
);

// We check the token
$checker->checkJWS($jws, 0);
```

**After**

```php
<?php
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Checker\ClaimCheckerManager;
use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Checker\ExpirationTimeChecker;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Algorithm\RS256;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\JWSTokenSupport;

$jsonConverter = new StandardConverter();
$serializer = new CompactSerializer($jsonConverter);

$jws = $serializer->unserialize($input);

$headerChecker = HeaderCheckerManager::create(
    [new AlgorithmChecker(['RS256'])], // A list of header checkers
    [new JWSTokenSupport()]            // A list of token support services (we only use the JWS token type here)
);

$algorithmManager = AlgorithmManager::create([
    new RS256(),
]);
$jwsVerifier = new JWSVerifier($algorithmManager);

$claimChecker = ClaimCheckerManager::create(
    [new ExpirationTimeChecker()] // A list of claim checkers
);

// We check all signatures
$isVerified = false;
for ($i = 0; $i < $jws->count(); $i++) {
    try {
        $headerChecker->check($jws, 0); // We check the header of the first (index=0) signature.        
        if ($jwsVerifier->verifyWithKey($jws, $key, 0)) { // We verify the signature
            $isVerified = true;
            break;
        }
    } catch (\Exception $e) {
        continue;
    }
}

if (!$isVerified) {
    //Unable to check the token. The header or the signature verification failed.
} else {
    // We check the claims.
    // If everything is ok, claims can be used.
    $claims = $jsonConverter->decode($jws->getPayload());
    $claimChecker->check($claims); // We check the claims.
}
```

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.


# Encrypted Tokens (JWE)

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`).

## Encryted Tokens Creation

**Before**

```php
<?php

use Jose\Factory\JWEFactory;
use Jose\Factory\JWKFactory;

// We want to encrypt a very important message
$message = 'Today, 8:00PM, train station.';
$jwe = JWEFactory::createJWEToCompactJSON(
    $message,                    // The message to encrypt
    $key,                        // The key of the recipient
    [                            // The shared protected header
        'alg' => 'RSA-OAEP-256',
        'enc' => 'A256CBC-HS512',
        'zip' => 'DEF',
    ]
);
```

**After**

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEBuilder;
use Jose\Component\Encryption\Serializer\CompactSerializer;

$keyEncryptionAlgorithmManager = AlgorithmManager::create([
    new RSAOAEP256(),
]);

$contentEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256CBCHS512(),
]);

$compressionMethodManager = CompressionMethodManager::create([
    new Deflate(),
]);

$jsonConverter = new StandardConverter();

$jweBuilder = new JWEBuilder(
    $jsonConverter,
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);

$message = 'Today, 8:00PM, train station.';

$jwe = $jweBuilder
    ->create()
    ->withPayload($message)
    ->withSharedProtectedHeader([
        'alg' => 'RSA-OAEP-256',
        'enc' => 'A256CBC-HS512',
        'zip' => 'DEF'
    ])
    ->addRecipient($jwk)
    ->build();

$serializer = new CompactSerializer($jsonConverter);

$token = $serializer->serialize($jwe, 0);
```

## Tokens Decryption

**Before**

```php
<?php
use Jose\Factory\JWKFactory;
use Jose\Loader;

// We create our loader.
$loader = new Loader();

// This is the input we want to load verify.
$input = 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0.rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs.-nBoKLH0YkLZPSI9.o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw.UCGiqJxhBI3IFVdPalHHvA';

// The payload is decrypted using our key.
$jwe = $loader->loadAndDecryptUsingKey(
    $input,            // The input to load and decrypt
    $jwk,              // The symmetric or private key 
    ['RSA-OAEP'],      // A list of allowed key encryption algorithms
    ['A256GCM'],       // A list of allowed content encryption algorithms
    $recipient_index   // If decrypted, this variable will be set with the recipient index used to decrypt
);
```

**After**

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEBuilder;
use Jose\Component\Encryption\Serializer\CompactSerializer;
use Jose\Component\Encryption\Serializer\JWESerializerManager;

$keyEncryptionAlgorithmManager = AlgorithmManager::create([
    new RSAOAEP256(),
]);

$contentEncryptionAlgorithmManager = AlgorithmManager::create([
    new A256CBCHS512(),
]);

$compressionMethodManager = CompressionMethodManager::create([
    new Deflate(),
]);

$jsonConverter = new StandardConverter();

$jweBuilder = new JWEBuilder(
    $jsonConverter,
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);

$serializerManager = JWESerializerManager::create([
    new CompactSerializer($jsonConverter),
]);

$token = 'eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.9RLpf3Gauf05QPNCMzPcH4XNBLmH0s3e-YWwOe57MTG844gnc-g2ywfXt_R0Q9qsR6WhkmQEhdLk2CBvfqr4ob4jFlvJK0yW.CCvfoTKO9tQlzCvbAuFAJg.PxrDlsbSRcxC5SuEJ84i9E9_R3tCyDQsEPTIllSCVxVcHiPOC2EdDlvUwYvznirYP6KMTdKMgLqxB4BwI3CWtys0fceSNxrEIu_uv1WhzJg.4DnyeLEAfB4I8Eq0UobnP8ymlX1UIfSSADaJCXr3RlU';

$jwe = $serializerManager->unserialize($token);

$jwe = $jweDecrypter->decryptUsingKey($jwe, $jwk);
```

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.


# Header Checking

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**

```php
<?php

use Jose\Checker\CheckerManager;
use Jose\Checker\AudienceChecker;
use Jose\Checker\CriticalHeaderChecker;

$checkerManager = new CheckerManager();
$checkerManager->addHeaderChecker(new AudienceChecker('My Server'));
$checkerManager->addHeaderChecker(new CriticalHeaderChecker());

$checkerManager->checkJWS($jws, $signature_index);
```

**After**

```php
<?php

use Jose\Component\Checker\AudienceChecker;
use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Signature\JWSTokenSupport;

$checkerManager = new HeaderCheckerManager();
$checkerManager->add(new AudienceChecker('My Service'));
$checkerManager->addTokenTypeSupport(new TokenSupport());
```

*Please note that the header* `crit` *is always checked.*


# Claim Checking

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**

```php
<?php

use Jose\Checker\CheckerManager;
use Jose\Checker\ExpirationTimeChecker;
use Jose\Checker\IssuedAtChecker;
use Jose\Checker\NotBeforeChecker;

$checkerManager = new CheckerManager();
$checkerManager->addClaimChecker(new ExpirationTimeChecker());
$checkerManager->addClaimChecker(new IssuedAtChecker());
$checkerManager->addClaimChecker(new NotBeforeChecker());

$checkerManager->checkJWS($jws, $signature_index);
```

**After**

```php
<?php

use Jose\Component\Checker\ClaimCheckerManager;
use Jose\Component\Checker\ExpirationTimeChecker;
use Jose\Component\Checker\IssuedAtChecker;
use Jose\Component\Checker\NotBeforeChecker;

$claimCheckerManager = new ClaimCheckerManager();
$claimCheckerManager->add(new ExpirationTimeChecker());
$claimCheckerManager->add(new IssuedAtChecker());
$claimCheckerManager->add(new NotBeforeChecker());

$claimCheckerManager->check($claims);
```


# Introduction

This project is a framework that provides an implementation of:

* JW**S** [JSON Web Signature (RFC 7515)](https://tools.ietf.org/html/rfc7515),
* JW**E** [JSON Web Encryption (RFC 7516)](http://tools.ietf.org/html/rfc7516),
* JW**K** [JSON Web Key (RFC 7517)](http://tools.ietf.org/html/rfc7517).
* JW**A** [JSON Web Algorithms (RFC 7518)](http://tools.ietf.org/html/rfc7518).
* JW**T** [JSON Web Token (RFC 7519)](https://tools.ietf.org/html/rfc7519),
* JSON Web Key Thumbprint ([RFC 7638](https://tools.ietf.org/html/rfc7638)).
* Unencoded Payload Option ([RFC7797](https://tools.ietf.org/html/rfc7797)).

It also provides:

* a Symfony bundle
* a standalone console application

## Licence

This project is release under [MIT licence](https://github.com/web-token/jwt-framework/tree/846e8752fef1f7276488f52f80e69fcef54f8acc/LICENSE.md).


# Provided Features

## Supported Input Types:

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](/2.x/advanced-topics-1/signed-tokens-and/detached-payload) is supported.

## Supported Serialization Modes

* Compact JSON Serialization Syntax for JWS and JWE
* Flattened JSON Serialization Syntax for JWS and JWE
* General JSON Serialization Syntax for JWS and JWE

## Supported Compression Methods

| Compression Method | Supported |
| ------------------ | --------- |
| Deflate (`DEF`)    | YES       |

## Supported Key Types (JWK)

| 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  |

JWK objects support JSON Web Key Thumbprint ([RFC 7638](https://tools.ietf.org/html/rfc7638)).

{% hint style="info" %}
A `none` key type for the `none` algorithm. It is used to explicitly allow this unsecured algorithm.
{% endhint %}

## Key Sets (JWKSet)

JWKSet is fully supported.

## Supported Signature Algorithms

| 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       | [With PHP 7.1, third party extension highly recommended](https://github.com/jedisct1/libsodium-php) |
| EdDSA with Ed448 curve   | NO        | No extension or built-in implementation available                                                   |

{% hint style="info" %}
Other signature algorithms like `RS1`, `HS1` or `HS256/64` are also available. These algorithms should be used for testing purpose only or for compatibility with old systems
{% endhint %}

## Supported Key Encryption Algorithms

| Key Encryption Algorithm                                      | Supported |
| ------------------------------------------------------------- | --------- |
| dir                                                           | YES       |
| RSA1\_5, RSA-OAEP and RSA-OAEP-256                            | YES       |
| 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        |

{% hint style="info" %}
Other encryption algorithms like `RSA-OEAP-384` or `ChaCha20-Poly1305` are also available. These algorithms should be used for testing purpose only or for compatibility with old systems
{% endhint %}

{% hint style="warning" %}
For the `ECDH-ES` with X25519 curve with PHP 7.1, the [third party extension highly recommended](https://github.com/jedisct1/libsodium-php)
{% endhint %}

{% hint style="danger" %}
The algorithms `RSA1_5` and `RSA-OAEP` are now deprecated. Please use with caution.
{% endhint %}

## Supported Content Encryption Algorithms

| Content Encryption Algorithm                   | Supported |
| ---------------------------------------------- | --------- |
| A128CBC+HS256, A192CBC+HS384 and A256CBC+HS512 | YES       |
| A128GCM, A192GCM and A256GCM                   | YES       |

{% hint style="info" %}
Other encryption algorithms like `A128CTR`, `A192CTR` and `A256CTR` are also available. These algorithms should be used for testing purpose only or for compatibility with old systems
{% endhint %}


# Pre-requisite

This framework needs at least:

* ![PHP 7.2+](https://img.shields.io/badge/PHP-7.2%2B-ff69b4.svg),
* 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](https://github.com/jedisct1/libsodium-php)


# Continous Integration

The framework has been successfully tested using `PHP 7.1`, `PHP 7.2` and `nightly` with all algorithms.

Tests vectors from the [RFC 7520](http://tools.ietf.org/html/rfc7520) 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](https://scrutinizer-ci.com/g/web-token/jwt-framework) and [Sensio Insight](https://insight.sensiolabs.com/projects/b7efa68f-8962-41cf-a2e3-4444426bc95a).

Coding Standards are verified by [StyleCI](https://styleci.io/repos/105997386).

Code coverage is analyzed by [Coveralls.io](https://coveralls.io/github/web-token/jwt-framework).


# Contributing

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](https://github.com/web-token/jwt-framework/labels/help+wanted) or [those that are easy to fix](https://github.com/web-token/jwt-framework/labels/easy-pick).

Do not forget to [follow these best practices](https://github.com/web-token/jwt-framework/tree/master/.github/CONTRIBUTING.md).

**If you think you have found a security issue, DO NOT open an issue**. [You MUST submit your issue here](https://gitter.im/Spomky/).


# The "Easy" Way

In version 2.1, an "Easy" component will be released. With this component you will be able to produce and consume tokens an easy way.

* Step 1: install the package `web-token/jwt-easy`
* Step 2: install the [signature](/2.x/the-components/signed-tokens-jws/signature-algorithms) or [encryption](/2.x/the-components/encrypted-tokens-jwe/encryption-algorithms) algorithms you want to use. e.g., `web-token/jwt-signature-algorithm-rsa`. if you do not, you may encounter an error like "The algorithm "ES256" is not supported."
* Step 3: create your scripts.

## JWS Creation And Verification

In the following example, we will create a signed token (JWS) with a set of standard and custom claims and headers.

```php
use Jose\Component\Core\JWK;
use Jose\Easy\Build;

$time = time(); // The current time

$jwk = new JWK([
    'kty' => 'RSA',
    'kid' => 'bilbo.baggins@hobbiton.example',
    'use' => 'sig',
    'n' => 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw',
    'e' => 'AQAB',
    'd' => 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ',
    'p' => '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k',
    'q' => 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc',
    'dp' => 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik',
    'dq' => 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8',
    'qi' => '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4',
]);
$jws = Build::jws() // We build a JWS
    ->exp($time + 3600) // The "exp" claim
    ->iat($time) // The "iat" claim
    ->nbf($time) // The "nbf" claim
    ->jti('0123456789', true) // The "jti" claim.
                              // The second argument indicate this pair shall be duplicated in the header
    ->alg('RS512') // The signature algorithm. A string or an algorithm class.
    ->iss('issuer') // The "iss" claim
    ->aud('audience1') // Add an audience ("aud" claim)
    ->aud('audience2') // Add another audience
    ->sub('subject') // The "sub" claim
    ->claim('https://example.com/isRoot', true)
    ->header('prefs', ['field1', 'field7'])
    ->sign($jwk) // Compute the token with the given JWK
;

//You can directly set the payload and the header at once

$jws = Build::jws() // We build a JWS
    ->payload([
        'exp' => $time + 3600, // The "exp" claim
        'iat' => $time, // The "iat" claim
        'nbf' => $time, // The "nbf" claim
        'jti' => '0123456789', // The "jti" claim
        'iss' => 'issuer', // The "iss" claim
        'aud' => ['audience1', 'audience2'], // Add an audience ("aud" claim)
        'sub' => 'subject', // The "sub" claim
        'https://example.com/isRoot' => true,
    ])
    ->header('prefs', ['field1', 'field7'])
    ->header('jti', '0123456789'),
    ->header('alg', 'RS512')
    ->sign($jwk)
;

echo $jws; // The variable $jws now contains your token
```

A token you receive can be read and verified. Verification is done on the signature and the claims or header parameters you want.

```php
use Jose\Component\Core\JWK;
use Jose\Easy\Load;

$jwk = new JWK([
    'kty' => 'RSA',
    'kid' => 'bilbo.baggins@hobbiton.example',
    'use' => 'sig',
    'n' => 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw',
    'e' => 'AQAB'
]);
$jwt = Load::jws($token) // We want to load and verify the token in the variable $token
    ->algs(['RS256', 'RS512']) // The algorithms allowed to be used
    ->exp() // We check the "exp" claim
    ->iat(10) // We check the "iat" claim. Leeway is 10s
    ->nbf() // We check the "nbf" claim
    ->aud('audience1') // Allowed audience
    ->iss('issuer') // Allowed issuer
    ->sub('subject') // Allowed subject
    ->jti('0123456789') // Token ID
    ->key($jwk) // Key used to verify the signature
    ->run() // Go!
;
```

If everything is ok, the variable `$jwt` contains a `Jose\Easy\JWT` object. This object has 2 properties: `header` and `claims` containing the loaded values.

```php
$jwt->claims->all(); // All claims (array)
$jwt->claims->iat(); // = $jwt->claims->get('iat');
$jwt->claims->nbf();
$jwt->claims->exp();
$jwt->claims->jti(); // '0123456789'
$jwt->claims->iss(); // 'issuer'
$jwt->claims->sub(); // 'subject'
$jwt->claims->aud(); // ['audience1', 'audience2']
$jwt->claims->get('https://example.com/isRoot'); // true

$jwt->header->all(); // ['jti' => '0123456789', 'alg' => 'RS512', 'crit' => ['alg']]
$jwt->header->alg(); // 'RS512'
$jwt->header->jti(); // '0123456789'
```

## JWE Creation And Decryption

The JWE creation and loading is very similar to the JWS process as they use common methods. In the following example, we will create an encrypted token (JWE) with a set of standard and custom claims and headers.

```php
use Jose\Component\Core\JWK;
use Jose\Easy\Build;

$time = time(); // The current time

$jwk = new JWK([
    'kty' => 'RSA',
    'kid' => 'bilbo.baggins@hobbiton.example',
    'use' => 'enc',
    'n' => 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw',
    'e' => 'AQAB',
]);
$jwe = Build::jwe() // We build a JWE
    ->exp($time + 3600)
    ->iat($time)
    ->nbf($time)
    ->jti('0123456789', true)
    ->iss('issuer')
    ->aud('audience1')
    ->aud('audience2')
    ->sub('subject')
    ->alg('RSA-OAEP-256') // The "alg" header parameter corresponds to the key encryption algorithm
    ->enc('A256GCM')      // The "enc" header parameter corresponds to the content encryption algorithm
    ->zip('DEF')          // We compress the payload (optional. Only recommended for large set of data)
    ->claim('is_root', true) // Custom claims
    ->claim('roles', ['ROLE1' => true, 'ROLE2' => 0.007])
    ->crit(['alg', 'enc']) // We mark some header parameters as critical
    ->encrypt($jwk) // Compute the token with the given JWK (public key)
;

echo $jwe; // The variable $jwe now contains your token
```

The encrypted tokens can be decrypted the same way as the signed ones.

```php
use Jose\Component\Core\JWK;
use Jose\Easy\Load;

$jwk = new JWK([
    'kty' => 'RSA',
    'kid' => 'bilbo.baggins@hobbiton.example',
    'use' => 'sig',
    'n' => 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw',
    'e' => 'AQAB',
    'd' => 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ',
    'p' => '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k',
    'q' => 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc',
    'dp' => 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik',
    'dq' => 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8',
    'qi' => '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4',
]);
$jwt = Load::jwe($token) // We want to load and decrypt the token in the variable $token
    ->algs(['RSA-OAEP-256', 'RSA-OAEP']) // The key encryption algorithms allowed to be used
    ->encs(['A256GCM']) // The content encryption algorithms allowed to be used
    ->exp()
    ->iat()
    ->nbf()
    ->aud('audience1')
    ->iss('issuer')
    ->sub('subject')
    ->jti('0123456789')
    ->key($jwk) // Key used to decrypt the token
    ->run() // Go!
;
```

If everything is ok, the variable `$jwt` contains a `Jose\Easy\JWT` object.


# Algorithm Management (JWA)

For each cryptographic operation you will perform, you will need at least one algorithm.

The algorithm list depends on the cypher operation to be performed (signature or encryption).

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`.

The algorithm management is part of the `web-token/jwt-core` component:

```bash
composer require web-token/jwt-core
```

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\ES512;

$algorithmManager = new AlgorithmManager([
    new PS256(),
    new ES512(),
]);
```

{% hint style="info" %}
The signature algorithms are available in other packages. See [signature](/2.x/the-components/signed-tokens-jws/signature-algorithms) or [encryption](/2.x/the-components/encrypted-tokens-jwe/encryption-algorithms) algorithm pages for more information
{% endhint %}

{% hint style="warning" %}
It is not possible to set the same algorithm twice in the same algorithm manager.
{% endhint %}

## Algorithm Manager Factory

Your application may need several algorithm managers for several use cases. For example you application may use JWT for:

* signed events,
* authentication tokens.

To avoid mixing algorithms in one algorithm manager or instantiate several times the same algorithms, this framework provides an **Algorithm Manager Factory**.

This factory will create algorithm managers on demand. It allows the same algorithm to be instantiated multiple times but with different configuration options.

Each algorithm is identified using an alias.

```php
<?php

use Jose\Component\Core\AlgorithmManagerFactory;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS512A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;

$algorithmManagerFactory = new AlgorithmManagerFactory();
$algorithmManagerFactory 
    ->add('PS256', new PS256())
    ->add('A128CBC-HS256', new A128CBCHS256())
    ->add('PBES2-HS512+A256KW', new PBES2HS512A256KW())
    ->add('PBES2-HS512+A256KW with custom configuration', new PBES2HS512A256KW(128, 8192))
;
```

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,
* &#x20;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`:

```php
<?php

$signatureAlgorithmManager = $algorithmManagerFactory ->create(['PS256']);
$encryptionAlgorithmManager = $algorithmManagerFactory ->create(['A128CBC-HS256', 'PBES2-HS512+A256KW']);
$encryptionAlgorithmManagerForParanoid = $algorithmManagerFactory ->create(['A128CBC-HS256', 'PBES2-HS512+A256KW with custom configuration']);
```


# Key (JWK) and Key Set (JWKSet)

To perform cryptographic operations (signature/verification and encryption/decryption), you will need keys.

The `JWK` object is part of the `web-token/jwt-core` component:

```bash
composer require web-token/jwt-core
```

## JWK

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.

## JWKSet

The keys can be grouped in key sets. A `JWKSet` object represents a key set. It can contain as many keys as you need.

{% hint style="warning" %}
We strongly recommend you to avoid mixing public, private or shared keys in the same key set.
{% endhint %}


# Key (JWK)

You can create a JWK object using two static methods:

* `new JWK(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.

{% hint style="warning" %}
Please note a JWK object is an immutable object
{% endhint %}

```php
<?php
// Check if the key has a parameter.
$jwk->has('kty');

// Retrieve the key parameter.
$jwk->get('kty');

// Retrieve all key parameters.
$jwk->all();

// Calculate the thumbprint of the key. Acceptable hash algorithms are those returned by the PHP function "hash_algos".
$jwk->thumbprint('sha256');

// If the key is a private key (RSA, EC, OKP), it can be converted into public:
$public_key = $jwk->toPublic();

// The JWK object can be serialized into JSON
json_encode($jwk);
```

## Generate A New Key

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.

```bash
composer require web-token/jwt-key-mgmt
```

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

{% hint style="info" %}
The `none` algorithm needs a key of type `none`. This is a specific key type that must only be used with this algorithm.
{% endhint %}

### Octet String

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).

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createOctKey(
    1024, // Size in bits of the key. We recommend at least 128 bits.
    [
        'alg' => 'HS256', // This key must only be used with the HS256 algorithm
        'use' => 'sig'    // This key is used for signature/verification operations only
    ]
);
```

If you already have a shared secret, you can use it to create an `oct` key:

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$jwk = JWKFactory::createFromSecret(
    'My Secret Key',       // The shared secret
    [                      // Optional additional members
        'alg' => 'HS256',
        'use' => 'sig'
    ]
);
```

### RSA Key Pair

The following example will show you how to create a `RSA` key.

The key size must be of 384 bits at least.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$private_key = JWKFactory::createRSAKey(
    4096, // Size in bits of the key. We recommend at least 2048 bits.
    [
        'alg' => 'RSA-OAEP-256', // This key must only be used with the RSA-OAEP-256 algorithm
        'use' => 'enc'    // This key is used for encryption/decryption operations only
    ]);
```

### Elliptic Curve Key Pair

The following example will show you how to create a `EC` key.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createECKey('P-256');
```

The supported curves are:

* `P-256`
* `P-384`
* `P-521` (note that this is **521** and not 512)

#### Octet Key Pair

The following example will show you how to create a `OKP` key.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createOKPKey('X25519');
```

The supported curves are:

* `Ed25519` for signature/verification only
* `X25519` for encryption/decryption only

### None Key

The `none` key type is a special type used only for the `none` algorithm.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createNoneKey();
```

## Create Key From External Sources

### From Values

In case you already have key values, you can create a key by passing those values as an argument:

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromValues([
    'kid' => '71ee230371d19630bc17fb90ccf20ae632ad8cf8',
    'kty' => 'RSA',
    'alg' => 'RS256',
    'use' => 'sig',
    'n' => 'vnMTRCMvsS04M1yaKR112aB8RxOkWHFixZO68wCRlVLxK4ugckXVD_Ebcq-kms1T2XpoWntVfBuX40r2GvcD9UsTFt_MZlgd1xyGwGV6U_tfQUll5mKxCPjr60h83LXKJ_zmLXIqkV8tAoIg78a5VRWoms_0Bn09DKT3-RBWFjk=',
    'e' => 'AQAB',
]);
```

### From A Key File

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.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromKeyFile(
    '/path/to/my/key/file.pem', // The filename
    'Secret',                   // Secret if the key is encrypted
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

### From A PKCS#12 Certificate

You can convert a PKCS#12 Certificate into a JWK. Encrypted certificates are also supported.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromPKCS12CertificateFile(
    '/path/to/my/key/file.p12', // The filename
    'Secret',                   // Secret if the key is encrypted
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

### From A X.509 Certificate

You can convert a X.509 Certificate into a JWK.

```php
<?php

use Jose\Component\KeyManagement\JWKFactory;

$key = JWKFactory::createFromCertificateFile(
    '/path/to/my/key/file.crt', // The filename
    [
        'use' => 'sig',         // Additional parameters
    ]
);
```

{% hint style="info" %}
Please note that X.509 certificates only contains public keys.
{% endhint %}


# Key Set (JWKSet)

You can create a JWKSet object using three static methods:

* `new JWKSet(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.

{% hint style="warning" %}
Please note a JWKSet object is an immutable object
{% endhint %}

```php
<?php
// Returns all keys
$jwkset->all();

// Check if the key set has the key with the key ID 'KEY ID'.
$jwkset->has('KEY ID');

// Retreive the key with the key ID 'KEY ID'.
$jwkset->get('KEY ID');

// Counts the keys in the key set.
$jwkset->count(); // The method count($jwkset) has the same behaviour.

// Adds a key to the key set.
// /!\ As the JWKSet object is immutable, this method will create a new key set. The previous key set is unchanged.
$newJwkset = $jwkset->with($jwk);

// Removes a key to the key set.
// /!\ As the JWKSet object is immutable, this method will create a new key set. The previous key set is unchanged.
$newJwkset = $jwkset->without('KEY ID');

// Selects a key according to the requirements.
// The first argument is the key usage ("sig" of "enc")
// The second argument is the algorithm to be used (optional)
// The third argument is an associative array this constraints (optional)
$key = $jwkset->selectKey('sig', $algorithm, ['kid' => 'KEY ID']);

// You can iterate on a key set
foreach($jwkset as $kid => $jwk) {
    // Action with the key done here
}

// The JWKSet object can be serialized into JSON
json_encode($jwkset);
```


# Header Checker

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:

```bash
composer require web-token/jwt-checker
```

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.&#x20;

## Header Checker 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.

```php
<?php

use Jose\Component\Checker\HeaderCheckerManager;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Signature\JWSTokenSupport;

$headerCheckerManager = new HeaderCheckerManager(
    [
        new AlgorithmChecker(['HS256']), // We check the header "alg" (algorithm)
    ],
    [
        new JWSTokenSupport(), // Adds JWS token type support
    ]
);
```

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.

```php
$headerCheckerManager->check($jwt, 0);
```

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.

```php
$headerCheckerManager->check($jwt, 0, ['alg', 'enc', 'crit']);
```

## Header Checker Manager Factory

The Header Checker Manager Factory will help you to create as many Header Checker Manager as you want to fit on your application requirements.

```php
<?php

use Jose\Component\Checker\HeaderCheckerManagerFactory;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Encryption\JWETokenSupport;
use Jose\Component\Signature\JWSTokenSupport;

$headerCheckerManagerFactory = new HeaderCheckerManagerFactory();
$headerCheckerManagerFactory->add('signature_alg', new AlgorithmChecker(['HS256']));
$headerCheckerManagerFactory->add('key_encryption_alg', new AlgorithmChecker(['RSA1_5']));
$headerCheckerManagerFactory->addTokenTypeSupport(new JWSTokenSupport());
$headerCheckerManagerFactory->addTokenTypeSupport(new JWETokenSupport());

$headerCheckerManagerForSignatures = $headerCheckerManagerFactory->create(['signature_alg']);
$headerCheckerManagerForEncryption = $headerCheckerManagerFactory->create(['key_encryption_alg']);
```

## Custom Header Checker

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](https://tools.ietf.org/html/rfc7519#section-5.3)
* `UnencodedPayloadChecker`: checks the `b64` header parameter. See [unencoded payload](/2.x/advanced-topics-1/signed-tokens-and/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`.

{% code title="Acme\Checker\CustomChecker.php" %}

```php
<?php

namespace Acme\Checker;

use Jose\Component\Checker\HeaderChecker;
use Jose\Component\Checker\InvalidHeaderException;

final class CustomChecker implements HeaderChecker
{
    public function checkHeader($value)
    {
        if (!is_array($value) || !in_array($value, ['foo', 'bar'])) {
            throw new InvalidHeaderException('Invalid header "custom".', 'custom', $value);
        }
    }

    // This header parameter name.
    public function supportedHeader(): string
    {
        return 'custom';
    }

    // This method indicates if this parameter must be in the protected header or not.
    public function protectedHeaderOnly(): bool
    {
        return true;
    }
}
```

{% endcode %}


# Claim Checker

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:

```bash
composer require web-token/jwt-checker
```

## Claim Checker Manager

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.

```php
<?php

use Jose\Component\Checker\ClaimCheckerManager;
use Jose\Component\Checker;

$claimCheckerManager = new ClaimCheckerManager(
    [
        new Checker\IssuedAtChecker(),
        new Checker\NotBeforeChecker(),
        new Checker\ExpirationTimeChecker(),
        new Checker\AudienceChecker('Audience'),
    ]
);
```

When instantiated, call the method `check` to check the claims of a JWT object. This method only accept an associative array. You have to retrieve this array by converting the JWT payload.

```php
$claims = json_decode($jwt->getPayload(), true);
$claimCheckerManager->check($claims);
```

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.

```php
$claimCheckerManager->check($claims, ['iss', 'sub', 'aud']);
```

## Custom Claim Checker

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`;

```php
<?php

declare(strict_types=1);

namespace Acme\Checker;

use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\InvalidClaimException;

/**
 * Class FooChecker.
 */
final class FooChecker implements ClaimChecker
{
    /**
     * {@inheritdoc}
     */
    public function checkClaim($value)
    {
        if (!is_string($value)) { // If the value is not a string, then we throw an exception
            throw new InvalidClaimException('The claim "foo" must be a string.', 'foo', $value);
        }
        if (!in_array($value, ['bar', 'bat'])) { // Check if the value is allowed
            throw new InvalidClaimException('The claim "foo" must be "bar" or "bat".', 'foo', $value);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function supportedClaim(): string
    {
        return 'foo'; //The claim to check.
    }
}
```

All done! Now you can instantiate your class and add it to your Claim Checker Manager.

## Replicating Claims as Header Parameters

The [RFC7516 section 5.3](https://tools.ietf.org/html/rfc7519#section-5.3) 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 [custom header checker](/2.x/the-components/header-checker). However, to avoid duplicated classes, your claim checker can implement the `Jose\Component\Checker\HeaderChecker` interface.

Have a look at the `IssuedAtChecker` or the `NotBeforeChecker` classes. These checkers can be used for claim and header checks.

## Claim Checker Manager Factory

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.

```php
<?php

use Jose\Component\Checker\ClaimCheckerManagerFactory;
use Jose\Component\Checker;

$claimCheckerManagerFactory = new ClaimCheckerManagerFactory();
$claimCheckerManagerFactory->add('iat', new Checker\IssuedAtChecker());
$claimCheckerManagerFactory->add('nbf', new Checker\NotBeforeChecker());
$claimCheckerManagerFactory->add('exp', new Checker\ExpirationTimeChecker());
$claimCheckerManagerFactory->add('aud1', new Checker\AudienceChecker('Audience for service #1'));
$claimCheckerManagerFactory->add('aud2', new Checker\AudienceChecker('Audience for service #2'));

$claimCheckerManager1 = $claimCheckerManagerFactory->create(['iat', 'exp', 'aud2']);
$claimCheckerManager2 = $claimCheckerManagerFactory->create(['aud1', 'exp']);
```


# Signed Tokens (JWS)

To use the signed tokens (JWS), you have to install the [`web-token/jwt-signature` component](https://github.com/web-token/jwt-signature).

```bash
composer require web-token/jwt-signature
```

This component provides lot of signature algorithms and classes to load and create signed tokens.

Please refer to [this signature algorithm table](/2.x/the-components/signed-tokens-jws/signature-algorithms) to know what algorithms are available.

Then, you will find an [example to create a signed token here](/2.x/the-components/signed-tokens-jws/jws-creation) and another [example to load and verify](/2.x/the-components/signed-tokens-jws/jws-loading) incoming tokens.


# Signature Algorithms

This framework comes with several signature algorithms. These algorithms are in the following namespace: `Jose\Component\Signature\Algorithm`.

* 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.
* `ES256K`: Elliptic curve secp256k1 support (v2.1+).

## How To Use

These algorithms have to be used with the [Algorithm Manager](/2.x/the-components/algorithm-management-jwa). They do not need any arguments.

Example:

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\ES512;
use Jose\Component\Signature\Algorithm\None;

$algorithm_manager = new AlgorithmManager([
    new PS256(),
    new ES512(),
    new None(),
]);
```


# JWS Creation

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 only requires the algorithm manager.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = new AlgorithmManager([
    new HS256(),
]);

// Our key.
$jwk = new JWK([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// We instantiate our JWS Builder.
$jwsBuilder = new JWSBuilder($algorithmManager);
```

Now let's create our first JWS object.

```php
// The payload we want to sign. The payload MUST be a string hence we use our JSON Converter.
$payload = json_encode([
    'iat' => time(),
    'nbf' => time(),
    'exp' => time() + 3600,
    'iss' => 'My service',
    'aud' => 'Your application',
]);

$jws = $jwsBuilder
    ->create()                               // We want to create a new JWS
    ->withPayload($payload)                  // We set the payload
    ->addSignature($jwk, ['alg' => 'HS256']) // We add a signature with a simple protected header
    ->build();                               // We build it
```

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!

```php
use Jose\Component\Signature\Serializer\CompactSerializer;

$serializer = new CompactSerializer(); // The serializer

$token = $serializer->serialize($jws, 0); // We serialize the signature at index 0 (we only have one signature).
```

All good! The variable `$token` now contains a string that should be something like this:

```
eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDc4OTY5OTIsIm5iZiI6MTUwNzg5Njk5MiwiZXhwIjoxNTA3OTAwNTkyLCJpc3MiOiJNeSBzZXJ2aWNlIiwiYXVkIjoiWW91ciBhcHBsaWNhdGlvbiJ9.eycp9PTdgO4WA-68-AMoHPwsKDr68NhjIQKz4lUkiI0
```

Other serialization modes exist. We will see them in the Advanced Topics section.


# JWS Loading

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.

## Serializer And Verifier

In the following example, we will try to load a signed token. We will only use the `HS256` algorithm.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSVerifier;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = new AlgorithmManager([
    new HS256(),
]);

// We instantiate our JWS Verifier.
$jwsVerifier = new JWSVerifier(
    $algorithmManager
);
```

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.

{% hint style="warning" %}
We do not check header parameters here, but it is very important to do it. This step is described in the [Header Checker section](/2.x/the-components/header-checker).
{% endhint %}

**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.**

```php
<?php

use Jose\Component\Core\JWK;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\Serializer\CompactSerializer;

// Our key.
$jwk = new JWK([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The serializer manager. We only use the JWS Compact Serialization Mode.
$serializerManager = new JWSSerializerManager([
    new CompactSerializer(),
]);

// The input we want to check
$token = 'eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDc4OTY5OTIsIm5iZiI6MTUwNzg5Njk5MiwiZXhwIjoxNTA3OTAwNTkyLCJpc3MiOiJNeSBzZXJ2aWNlIiwiYXVkIjoiWW91ciBhcHBsaWNhdGlvbiJ9.eycp9PTdgO4WA-68-AMoHPwsKDr68NhjIQKz4lUkiI0';

// We try to load the token.
$jws = $serializerManager->unserialize($token);

// We verify the signature. This method does NOT check the header.
// The arguments are:
// - The JWS object,
// - The key,
// - The index of the signature to check. See 
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);
```

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.

## JWSLoader Object

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.

```php
<?php

use Jose\Component\Signature\JWSLoader;

$jwsLoader = new JWSLoader(
    $serializerManager,
    $jwsVerifier,
    $headerCheckerManager
);

$jws = $jwsLoader->loadAndVerifyWithKey($token, $jwk, $signature, $payload);
```

In case you use a key set, you can use the method `loadAndVerifyWithKeySet`.

## JWSLoaderFactory Object

> 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)

```php
<?php

use Jose\Component\Signature\JWSLoaderFactory;

$jwsLoaderFactory = new JWSLoaderFactory(
    $jwsSerializerManagerFactory,
    $jwsVerifierFactory,
    $headerCheckerManagerFactory
);

$jwsLoader = $jwsLoaderFactory->create(
    ['jws_compact'], // List of serializer aliases
    ['HS256'],       // List of signature algorithm aliases
    ['alg']          // Optional list of header checker aliases
);
```


# Encrypted Tokens (JWE)

To use the encrypted tokens (JWE), you have to install the [`web-token/jwt-encryption` component](https://github.com/web-token/jwt-encryption).

```bash
composer require web-token/jwt-encryption
```

This component provides lot of encryption algorithms and classes to load and create encrypted tokens.

Please refer to [this encryption algorithm table](/2.x/the-components/encrypted-tokens-jwe/encryption-algorithms) to know what algorithms are available.

Then, you will find an [example to create an encrypted token here](/2.x/the-components/encrypted-tokens-jwe/jwe-creation) and another [example to load and decrypt](/2.x/the-components/encrypted-tokens-jwe/jwe-loading) incoming tokens.


# Encryption Algorithms

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

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+A256KW` (class `PBES2HS512A256KW`)
* 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`)

{% hint style="danger" %}
The algorithm `RSA1_5` is deprecated due to known [security vulnerability](https://en.wikipedia.org/wiki/Adaptive_chosen-ciphertext_attack).

The algorithms `ECDH-ES*` are not recommended unless used with the `OKP` key type.
{% endhint %}

## Experimental Algorithms

The following 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.

## How To Use

These algorithms have to be used with the [Algorithm Manager](/2.x/the-components/algorithm-management-jwa).

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A128KW;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;

$algorithmManager = new AlgorithmManager([
    new A128KW(),
    new PBES2HS256A128KW(),
    new A128CBCHS256(),
]);
```

By default, `PBES2*` algorithms use the following parameter values:

* Salt size: 64 bytes (512 bits)
* Count: 4096&#x20;

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:

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW;

$algorithmManager = new AlgorithmManager([
    new PBES2HS256A128KW(16, 1024),
]);
```


# JWE Creation

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.

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEBuilder;

// The key encryption algorithm manager with the A256KW algorithm.
$keyEncryptionAlgorithmManager = new AlgorithmManager([
    new A256KW(),
]);

// The content encryption algorithm manager with the A256CBC-HS256 algorithm.
$contentEncryptionAlgorithmManager = new AlgorithmManager([
    new A256CBCHS512(),
]);

// The compression method manager with the DEF (Deflate) method.
$compressionMethodManager = new CompressionMethodManager([
    new Deflate(),
]);

// We instantiate our JWE Builder.
$jweBuilder = new JWEBuilder(
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);
```

Now let's create our first JWE object.

```php
use Jose\Component\Core\JWK;

// Our key.
$jwk = new JWK([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The payload we want to encrypt. It MUST be a string.
$payload = json_encode([
    'iat' => time(),
    'nbf' => time(),
    'exp' => time() + 3600,
    'iss' => 'My service',
    'aud' => 'Your application',
]);

$jwe = $jweBuilder
    ->create()              // We want to create a new JWE
    ->withPayload($payload) // We set the payload
    ->withSharedProtectedHeader([
        'alg' => 'A256KW',        // Key Encryption Algorithm
        'enc' => 'A256CBC-HS512', // Content Encryption Algorithm
        'zip' => 'DEF'            // We enable the compression (irrelevant as the payload is small, just for the example).
    ])
    ->addRecipient($jwk)    // We add a recipient (a shared key or public key).
    ->build();              // We build it
```

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!

```php
use Jose\Component\Encryption\Serializer\CompactSerializer;

$serializer = new CompactSerializer(); // The serializer

$token = $serializer->serialize($jwe, 0); // We serialize the recipient at index 0 (we only have one recipient).
```

All good! The variable `$token` now contains a string that should be something like that:

```php
eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.9RLpf3Gauf05QPNCMzPcH4XNBLmH0s3e-YWwOe57MTG844gnc-g2ywfXt_R0Q9qsR6WhkmQEhdLk2CBvfqr4ob4jFlvJK0yW.CCvfoTKO9tQlzCvbAuFAJg.PxrDlsbSRcxC5SuEJ84i9E9_R3tCyDQsEPTIllSCVxVcHiPOC2EdDlvUwYvznirYP6KMTdKMgLqxB4BwI3CWtys0fceSNxrEIu_uv1WhzJg.4DnyeLEAfB4I8Eq0UobnP8ymlX1UIfSSADaJCXr3RlU
```


# JWE Loading

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](/2.x/the-components/encrypted-tokens-jwe/jwe-creation).

```php
<?php

use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Encryption\Algorithm\KeyEncryption\A256KW;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;

// The key encryption algorithm manager with the A256KW algorithm.
$keyEncryptionAlgorithmManager = new AlgorithmManager([
    new A256KW(),
]);

// The content encryption algorithm manager with the A256CBC-HS256 algorithm.
$contentEncryptionAlgorithmManager = new AlgorithmManager([
    new A256CBCHS512(),
]);

// The compression method manager with the DEF (Deflate) method.
$compressionMethodManager = new CompressionMethodManager([
    new Deflate(),
]);

// We instantiate our JWE Decrypter.
$jweDecrypter = new JWEDecrypter(
    $keyEncryptionAlgorithmManager,
    $contentEncryptionAlgorithmManager,
    $compressionMethodManager
);
```

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.

{% hint style="warning" %}
We do not check header parameters here, but it is very important to do it. This step is described in the [Header Checker](/2.x/the-components/header-checker) section.
{% endhint %}

**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.**

```php
<?php

use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Encryption\Serializer\CompactSerializer;

// Our key.
$jwk = JWK::create([
    'kty' => 'oct',
    'k' => 'dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g',
]);

// The serializer manager. We only use the JWE Compact Serialization Mode.
$serializerManager = new JWESerializerManager([
    new CompactSerializer(),
]);

// The input we want to decrypt
$token = 'eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiemlwIjoiREVGIn0.9RLpf3Gauf05QPNCMzPcH4XNBLmH0s3e-YWwOe57MTG844gnc-g2ywfXt_R0Q9qsR6WhkmQEhdLk2CBvfqr4ob4jFlvJK0yW.CCvfoTKO9tQlzCvbAuFAJg.PxrDlsbSRcxC5SuEJ84i9E9_R3tCyDQsEPTIllSCVxVcHiPOC2EdDlvUwYvznirYP6KMTdKMgLqxB4BwI3CWtys0fceSNxrEIu_uv1WhzJg.4DnyeLEAfB4I8Eq0UobnP8ymlX1UIfSSADaJCXr3RlU';

// We try to load the token.
$jwe = $serializerManager->unserialize($token);

// We decrypt the token. This method does NOT check the header.
$success = $jweDecrypter->decryptUsingKey($jwe, $jwk, 0);
```

OK so if not exception is thrown, then your token is loaded and the payload correctly decrypted.

## JWELoader Object

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.

```php
<?php

use Jose\Component\Encryption\JWELoader;

$jweLoader = new JWELoader(
    $serializerManager,
    $jweDecrypter,
    $headerCheckerManager
);

$jwe = $jweLoader->loadAndDecryptWithKey($token, $key, $recipient);
```

In case you use a key set, you can use the method `loadAndDecryptWithKeySet`.

## JWELoaderFactory Object

> 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)

```php
<?php

use Jose\Component\Encryption\JWELoaderFactory;

$jweLoaderFactory = new JWELoaderFactory(
    $jweSerializerManagerFactory,
    $jweDecrypterFactory,
    $headerCheckerManagerFactory
);

$jweLoader = $jweLoaderFactory->create(
    ['jwe_compact'], // List of serializer aliases
    ['A128KW'],      // List of key encryption algorithm aliases
    ['A128KW'],      // List of content encryption algorithm aliases
    ['DEF'],         // List of compression method aliases
    ['alg', 'enc']   // Optional list of header checker aliases
);
```


# Symfony Bundle

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:

```php
/**
 * {@inheritdoc}
 */
public function registerBundles()
{
    $bundles = [
        ...
        new Jose\Bundle\JoseFramework\JoseFrameworkBundle(),
    ];

    return $bundles;
}
```

The bundle capabilities will depend on the components installed in your application. The core component is always available.

* [Algorithm Management](/2.x/the-symfony-bundle/algorithm-management)
* [Header and Claim Checkers](/2.x/the-symfony-bundle/header-and-claim-checker-management)
* [Keys and key sets](/2.x/the-symfony-bundle/key-and-key-set-management)
* [Signed tokens](/2.x/the-symfony-bundle/signed-tokens)
* [Encrypted tokens](/2.x/the-symfony-bundle/encrypted-tokens)


# Algorithm Management

## Algorithm Manager Factory Service

The Symfony Bundle provides an Algorithm Manager Factory service. The available algorithms depends on the components installed on your application.

```php
<?php

use Jose\Component\Core\AlgorithmManagerFactory;

$algorithmManagerFactory = $container->get(AlgorithmManagerFactory::class);
$algorithmManager = $algorithmManagerFactory->create(['RS256', 'HS512']);
```

## Custom Algorithm

This factory handles all algorithms services tagged with `jose.algorithm`.

Example:

```yaml
services:
    Acme\Bundle\Algorithm\FooAlgorihtm:
        tags:
            - {'name': 'jose.algorithm', 'alias': 'FOO'}
```

Your algorithm will be available through the algorithm manager factory service and the alias `FOO`.

## PBES2-\* Algorithms

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:

```yaml
services:
    my.custom.PBES2HS256A128KW.algorithm:
        class: Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS256A128KW
        arguments:
            - 128   # salt size
            - 10240 # counts
        tags:
            - {'name': 'jose.algorithm', 'alias': 'Ultra-Secured PBES2-HS256+A128KW'}
```

You can now use your custom alias:

```php
$algorithmManager = $algorithmManagerFactory->create(['Ultra-Secured PBES2-HS256+A128KW']);
```


# Key and Key Set Management

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:

```yaml
parameters:
    my_private_key: '%env(jwk:MY_PRIVATE_KEY)%'
    my_public_keyset: '%env(jwkset:MY_PUBLIC_KEYSET)%'
```

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:

```bash
composer require web-token/jwt-key-mgmt
```

* [Key Management (JWK)](/2.x/the-symfony-bundle/key-and-key-set-management/key-management-jwk)
* [Key Set Management (JWKSet)](/2.x/the-symfony-bundle/key-and-key-set-management/key-set-management-jwkset)


# Key Management (JWK)

## Keys As Services

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:

```yaml
jose: # Configuration of the JWT Framework
    keys: # Configuration of the keys
        key_name: # Unique key name
            method_name: # Name of the method
                ...
                is_public: true
```

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.

### From A Shared Secret

This method will directly get a shared secret.

```yaml
jose:
    keys:
        key_name:
            secret: # Method
                secret: 'This is my shared secret'
                additional_values:
                    use: 'sig'
                    alg: 'RS512'
```

### From A JWK Object

This method will directly load a JWK object.

```yaml
jose:
    keys:
        key_name:
            jwk: # Method
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
```

### From A X509 Certificate File

This method will load a X509 Certificate file.

```yaml
jose:
    keys:
        key_name:
            certificate: # Method
                path: '/path/to/your/X509/certificate'
                additional_values: # Optional values
                    use: 'sig'
                    alg: 'RS256'
```

### From A X509 Certificate

This method will load a key from a X509 Certificate.

```yaml
jose:
    keys:
        key_name:
            x5c: # Method
                value: '-----BEGIN CERTIFICATE----- ....'
                additional_values: # Optional values.
                    use: 'sig'
                    alg: 'RS256'
```

### From A PKCS#1/PKCS#8 Key File

This method will load a key from a PKCS#1 or PKCS#8 key file.

```yaml
jose:
    keys:
        key_name:
            file: # Method
                path: '/path/to/your/key/file'
                password: 'secret' # Optional. Only if the key is encrypted
                additional_values: # Optional values.
                    use: 'sig'
                    alg: 'RS256'
```

### From A Key In A Key Set

This method will retrieve a key from a JWKSet service.

```yaml
jose:
    keys:
        key_name:
            jwkset: # Method
                key_set: 'jose.key_set.my_key_set' # JWKSet service
                index: 0 # Use key at index 0
```

## Custom Tags

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        key_name:
            jwk: # Method
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Key Set Management (JWKSet)

## Key Sets As Services

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:

```yaml
jose: # Configuration of the JWT Framework
    key_sets: # Configuration of the keys
        keyset_name: # Unique key name
            method_name: # Name of the method
                ...
                is_public: true
```

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.

### From A JWKSet Object

This method will directly get a JWKSet object.

```yaml
jose:
    key_sets:
        key_name:
            jwkset: # Method
                value: '{"keys":[{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"},{"kty":"oct","k":"bwIAv5Nn-fo8p4LCEvM4IR9eLXgzJRs8jXCLb3xR0tDJGiZ46KheO4ip6htFKyN2aqJqlNi9-7hB6I1aLLy1IRT9-vcBoCSGu977cNAUuRLkRp7vo8s6MsxhB8WvQBDRZghV7jIYaune-3vbE7iDU2AESr8BUtorckLoO9uW__fIabaa3hJMMQIHCzYQbJKZvlCRCKWMk2H_zuS4JeDFTvyZH1skJYF_TET1DrCZHMPicw-Yk3_m2P-ilC-yidPPoVzeU8Jj3tQ6gtX3975qiQW7pt2qbgjKAuq2wsz_9hxLBtMB5rQPafFoxop7O4BklvZ9-ECcK6dfI2CAx9_tjQ"}]}'
```

### Distant Key Sets

You can load key sets shared by a distant service (e.g. Google, Microsoft, Okta...). You must install and enable the [Httplug Bundle](http://docs.php-http.org/en/latest/integrations/symfony-bundle.html).

When done, you have to create a client and enable the JKU Factory service by indicating the request factory service to use:

```yaml
httplug: # Example of client configuration
    plugins:
        cache: # We use the cache plugin
            cache_pool: 'cache.app' # We use the PSR-6 Cache service of the application
            config:
                default_ttl: 1800 # TTL set to 30 min
    clients:
        acme:
            factory: 'httplug.factory.guzzle6'
            plugins: ['httplug.plugin.cache'] # We enable the cache plugin for that client.

jose:
    jku_factory:
        enabled: true
        client: 'httplug.client.acme' # The Httplug client
        request_factory: 'httplug.message_factory' # In general, you will use the same message factory as the one used by Httplug
```

**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.

#### From A JKU (JWK Url)

The following example will allow you tu load a key set from a distant URI. The key set must be a JWKSet object.

```yaml
jose:
    key_sets:
        key_name:
            jku: # Method
                url: 'https://login.microsoftonline.com/common/discovery/keys'
```

#### From A X5U (X509 Certificates Url)

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.

```yaml
jose:
    key_sets:
        key_name:
            x5u: # Method
                url: 'https://www.googleapis.com/oauth2/v1/certs'
```

## Shared Key Sets

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 can enable these routes by adding the following configuration to your routing file.

```yaml
# config/routes.yaml
jwkset_endpoints:
    resource: "@JoseFrameworkBundle/Resources/config/routing/jwkset_controller.php"
```

Then you can share your key set.

```yaml
jose:
    key_sets:
        public_keyset: # The key set we want to share
            jwkset:
                value: '{"keys":[{"kty":"OKP","crv":"X25519","x":"ovuZiVcMXBN4r0VgCvJy_ChAsBv4YPJGC5w56PzndXY"},{"kty":"OKP","crv":"X25519","x":"4qyOJ4T9RkdciIn6LDxb2LdM1Ov-dtBSuj0jh6nCuyc"}]}'
    jwk_uris:
        shared_keyset:
            id: 'jose.key_set.public_keyset' # The key set service to share
            path: '/certs' # Path of the key set. Final path is hostname/route_prefix/path: https://www.foo.com/keys/certs
```

Now when you go to the URL `http://128.0.0.1:8000/certs`, you will get your key set.

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    key_sets:
        key_name:
            jku: # Method
                url: 'https://login.microsoftonline.com/common/discovery/keys'
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Header and Claim Checker Management

## Checker Manager Factory Services

The Symfony Bundle provides Header and Claim Checker Manager Factory services. These services are available when the `web-token/jwt-checker` component is installed:

```bash
composer require web-token/jwt-checker
```

```php
<?php

use Jose\Component\Checker\HeaderCheckerManagerFactory;
use Jose\Component\Checker\ClaimCheckerManagerFactory;

$headerCheckerManagerFactory = $container->get(HeaderCheckerManagerFactory::class);
$headerCheckerManager = $headerCheckerManagerFactory->create([...]);

$claimCheckerManagerFactory = $container->get(ClaimCheckerManagerFactory::class);
$claimCheckerManager = $claimCheckerManagerFactory->create([...]);
```

## Checker Manager Services

You can create Header and Claim Checker Managers using the bundle configuration.

```yaml
jose:
    checkers:
        claims:
            checker1:
                is_public: true
                claims: [...]
        headers:
            checker1:
                is_public: true
                headers: [...]
```

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.

## Custom Header Or Claim Checker

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`.

```yaml
services
    Acme\Checker\CustomHeaderChecker:
        public: false
        tags:
            - { name: 'jose.checker.header', alias: 'foo' }
    Acme\Checker\CustomClaimChecker:
        public: false
        tags:
            - { name: 'jose.checker.claim', alias: 'bar' }
```

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`.

## Custom Tags

You can add custom tags and attributes to the header and claim checker managers.

```yaml
jose:
    checkers:
        claims:
            checker1:
                claims: [...]
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# Signed Tokens

To use the signed tokens (JWS), you have to install the [`web-token/jwt-signature` component](https://github.com/web-token/jwt-signature).

```bash
composer require web-token/jwt-signature
```

When this component is installed, signature algorithms are automatically handles by the Algorithm Manager Factory.

* [JWS serializers](/2.x/the-symfony-bundle/signed-tokens/jws-serializers),
* [JWS creation](/2.x/the-symfony-bundle/signed-tokens/jws-creation),
* [JWS verification](/2.x/the-symfony-bundle/signed-tokens/jws-verification).

You can use `symfony/serializer` to serialize/unserialize your tokens:

```php
// $serializer corresponds to the Symfony serializer
$serializer->serialize($data, 'jws_compact');
```


# JWS serializers

## JWS Serializer Manager Factory Service

A `JWSSerializerManagerFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSSerializerManagerFactory;

$jwsSerializerManagerFactory = $container->get(JWSSerializerManagerFactory::class);
```

With this factory, you will be able to create the JWSSerializerManager you need:

```php
$jwsSerializerManager = $jwsSerializerManagerFactory->create(['jws_compact']);
```

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`

## JWS Serializer Manager As Service

There is also another way to create a JWSSerializerManager object: using the bundle configuration.

```yaml
jose:
    jws:
        serializers:
            serializer1:
                serializers: ['jws_compact']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Serializer Manager service named `jose.jws_serializer.serializer1` with selected serialization modes.

```php
<?php
$jwsSerializerManager = $container->get('jose.jws_serializer.serializer1');
```

## Custom Tags

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        serializers:
            serializer1:
                serializers: ['jws_compact']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWS creation

## JWS Builder Factory Service

A `JWSBuilderFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSBuilderFactory;

$jwsBuilderFactory = $container->get(JWSBuilderFactory::class);
```

With this factory, you will be able to create the JWSBuilder you need:

```php
$jwsBuilder = $jwsBuilderFactory->create(['HS256']);
```

You can now use the JWSBuilder as explained in the JWS Creation section.

## JWS Builder As Service

There is also another way to create a JWSBuilder object: using the bundle configuration.

```yaml
jose:
    jws:
        builders:
            builder1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Builder service named `jose.jws_builder.builder1` with selected signature algorithms.

```php
<?php
$jwsBuilder = $container->get('jose.jws_builder.builder1');
```

## Custom Tags

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        builders:
            builder1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWS verification

## JWS Verifier Factory Service

A `JWSVerifierFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Signature\JWSVerifierFactory;

$jwsVerifierFactory = $container->get(JWSVerifierFactory::class);
```

With this factory, you will be able to create the JWSVerifier you need:

```php
$jwsVerifier = $jwsVerifierFactory->create(['HS256']);
```

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.**

## JWS Verifier As Service

There is also another way to create a JWSVerifier object: using the bundle configuration.

```yaml
jose:
    jws:
        verifiers:
            verifier1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                is_public: true
```

With the previous configuration, the bundle will create a public JWS Verifier service named `jose.jws_verifier.verifier1` with selected signature algorithms.

```php
<?php
$jwsVerifier = $container->get('jose.jws_verifier.verifier1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jws:
        verifiers:
            verifier1:
                signature_algorithms: ['HS256', 'RS256', 'ES256']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

## JWS Loader Service

> This feature was introduced in version 1.1.

The [`JWSLoaderFactory`](/2.x/the-components/signed-tokens-jws/jws-loading) 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.

```php
<?php
use Jose\Component\Signature\JWSLoaderFactory;

$jwsLoaderFactory = $container->get(JWSLoaderFactory::class);
```

You can also create `JWSLoader` objects as services using the configuration of the bundle.

```yaml
jose:
    jws:
        loaders:
            jws_loader1:
                serializers: ['jws_compact']
                signature_algorithms: ['HS256']
                header_checkers: ['alg']
                is_public: true
```

Or using the [`ConfigurationHelper`](/2.x/the-symfony-bundle/configuration-helper).

```php
<?php
use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;

...
ConfigurationHelper::addJWSLoader($container, 'jws_loader1', ['jws_compact'], ['HS256'], ['alg'], true);
```


# Encrypted Tokens

To use the encrypted tokens (JWE), you have to install the [`web-token/jwt-encryption` component](https://github.com/web-token/jwt-encryption).

```bash
composer require web-token/jwt-encryption
```

When this component is installed, encryption algorithms are automatically handles by the Algorithm Manager Factory.

* [JWE serializers](/2.x/the-symfony-bundle/encrypted-tokens/jwe-serializers),
* [JWE creation](/2.x/the-symfony-bundle/encrypted-tokens/jwe-creation),
* [JWE decryption](/2.x/the-symfony-bundle/encrypted-tokens/jwe-decryption).

You can use `symfony/serializer` to serialize/unserialize your tokens:

```php
// $serializer corresponds to the Symfony serializer
$serializer->serialize($data, 'jwe_compact');
```


# JWE serializers

## JWE Serializer Manager Factory Service

A `JWESerializerManagerFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWESerializerManagerFactory;

$jweSerializerManagerFactory = $container->get(JWESerializerManagerFactory::class);
```

With this factory, you will be able to create the JWESerializerManager you need:

```php
$jweSerializerManager = $jweSerializerManagerFactory->create(['jwe_compact']);
```

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`

## JWE Serializer Manager As Service

There is also another way to create a JWESerializerManager object: using the bundle configuration.

```yaml
jose:
    jwe:
        serializers:
            serializer1:
                serializers: ['jwe_compact']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Serializer Manager service named `jose.jwe_serializer.serializer1` with selected serialization modes.

```php
<?php
$jweSerializerManager = $container->get('jose.jwe_serializer.serializer1');
```

## Custom Tags

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        serializers:
            serializer1:
                serializers: ['jwe_compact']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWE creation

## JWE Builder Factory Service

A `JWEBuilderFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWEBuilderFactory;

$jweBuilderFactory = $container->get(JWEBuilderFactory::class);
```

With this factory, you will be able to create the JWEBuilder you need:

```php
$jweBuilder = $jweBuilderFactory->create(
    ['A256GCMKW'],
    ['A256CBC-HS256'],
    ['DEF'] // Compression methods
);
```

Available compression methods are:

* `DEF`: deflate (recommended)
* `GZ`: gzip
* `ZLIB`: zlib

You can now use the JWEBuilder as explained in the JWE Creation section.

## JWE Builder As Service

There is also another way to create a JWEBuilder object: using the bundle configuration.

```yaml
jose:
    jwe:
        builders:
            builder1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Builder service named `jose.jwe_builder.builder1` with selected encryption algorithms.

```php
<?php
$jweBuilder = $container->get('jose.jwe_builder.builder1');
```

## Custom Tags

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        builders:
            builder1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```


# JWE decryption

## JWE Decrypter Factory Service

A `JWEDecrypterFactory` is available as a service in your application container:

```php
<?php
use Jose\Component\Encryption\JWEDecrypterFactory;

$jweDecrypterFactory = $container->get(JWEDecrypterFactory::class);
```

With this factory, you will be able to create the JWEDecrypter you need:

```php
$jweDecrypter = $jweDecrypterFactory->create(['HS256']);
```

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.**

## JWE Decrypter As Service

There is also another way to create a JWEDecrypter object: using the bundle configuration.

```yaml
jose:
    jwe:
        decrypters:
            decrypter1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                is_public: true
```

With the previous configuration, the bundle will create a public JWE Decrypter service named `jose.jwe_decrypter.decrypter1` with selected encryption algorithms.

```php
<?php
$jweDecrypter = $container->get('jose.jwe_decrypter.decrypter1');
```

## Custom Tags

> This feature was introduced in version 1.1.

You can add custom tags and attributes to the services you create.

```yaml
jose:
    jwe:
        decrypters:
            decrypter1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

## JWE Loader Service

The [`JWELoaderFactory`](/2.x/the-components/encrypted-tokens-jwe/jwe-loading) 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.

```php
<?php
use Jose\Component\Encryption\JWELoaderFactory;

$jweLoaderFactory = $container->get(JWELoaderFactory::class);
```

You can also create `JWELoader` objects as services using the configuration of the bundle.

```yaml
jose:
    jwe:
        loaders:
            jwe_loader1:
                key_encryption_algorithms: ['A256GCMKW']
                content_encryption_algorithms: ['A256CBC-HS256']
                compression_methods: ['DEF']
                header_checkers: ['alg', 'enc']
                is_public: true
```

Or using the [`ConfigurationHelper`](/2.x/the-symfony-bundle/configuration-helper).

```php
<?php
use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;

...
ConfigurationHelper::addJWELoader($container, 'jwe_loader1', ['jwe_compact'], ['A256GCMKW'], ['A256CBC-HS256'], ['DEF'], ['alg', 'enc'], true);
```


# Configuration Helper

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`).

```php
<?php

declare(strict_types=1);

namespace AcmeBundle\DependencyInjection;

use Jose\Bundle\JoseFramework\Helper\ConfigurationHelper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

final class AcmeExtension extends Extension implements PrependExtensionInterface
{
    ...

    /**
     * {@inheritdoc}
     */
    public function prepend(ContainerBuilder $container)
    {
        ... // The Helper will be called here
    }
}
```

Let say you want to create a JWK as a service:

```php
ConfigurationHelper::addKey(
    $container,
    'acme_my_key',
    'jwk', [
        'value' => '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}',
        'is_public' => true,
    ],
    [
        'tag_name1' => [],
        'tag_name2' => ['attribute1' => 'foo'],
    ]
);
```

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:

```yaml
jose:
    keys:
        acme_my_key:
            jwk:
                value: '{"kty":"oct","k":"dzI6nbW4OcNF-AtfxGAmuyz7IpHRudBI0WgGjZWgaRJt6prBn3DARXgUR8NVwKhfL43QBIU2Un3AvCGCHRgY4TbEqhOi8-i98xxmCggNjde4oaW6wkJ2NgM3Ss9SOX9zS3lcVzdCMdum-RwVJ301kbin4UtGztuzJBeg5oVN00MGxjC2xWwyI0tgXVs-zJs5WlafCuGfX1HrVkIf5bvpE0MQCSjdJpSeVao6-RSTYDajZf7T88a2eVjeW31mMAg-jzAWfUrii61T_bYPJFOXW8kkRWoa1InLRdG6bKB9wQs9-VdXZP60Q4Yuj_WZ-lO7qV9AEFrUkkjpaDgZT86w2g"}'
                is_public: true
                tags:
                    tag_name1: ~
                    tag_name2: {attribute1: 'foo'}
```

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](https://github.com/Spomky-Labs/lexik-jose-bridge/blob/v2.0/DependencyInjection/SpomkyLabsLexikJoseExtension.php#L78) to see how we configure the Jose Bundle without dedicated configuration


# Events

How to use Symfony events

With the version 2.0 of the Symfony Bundle, you will be able to listen or subscribe to events.

All events can be found in the class `Jose\Bundle\JoseFramework\Event\Events`.

* **JWS:**
  * Events::JWS\_BUILT\_SUCCESS
  * Events::JWS\_BUILT\_FAILURE
  * Events::JWS\_VERIFICATION\_SUCCESS
  * Events::JWS\_VERIFICATION\_FAILURE
  * Events::JWS\_LOADING\_SUCCESS
  * Events::JWS\_LOADING\_FAILURE
* **JWE:**
  * Events::JWE\_BUILT\_SUCCESS
  * Events::JWE\_BUILT\_FAILURE
  * Events::JWE\_DECRYPTION\_SUCCESS
  * Events::JWE\_DECRYPTION\_FAILURE
  * Events::JWE\_LOADING\_SUCCESS
  * Events::JWE\_LOADING\_FAILURE
* **Nested Tokens:**
  * Events::NESTED\_TOKEN\_ISSUED Events::NESTED\_TOKEN\_LOADING\_SUCCESS Events::NESTED\_TOKEN\_LOADING\_FAILURE
* **Checked Header:**
  * Events::HEADER\_CHECK\_SUCCESS
  * Events::HEADER\_CHECK\_FAILURE
* **Checked Claim:**
  * Events::CLAIM\_CHECK\_SUCCESS
  * Events::CLAIM\_CHECK\_FAILURE

## Example:

{% code title="App\EventSubscriber\JwsSubscriber.php" %}

```php
<?php

declare(strict_types=1);

namespace App\EventSubscriber;

use Jose\Bundle\JoseFramework\Event\Events;
use Jose\Bundle\JoseFramework\Event\JWSBuiltSuccessEvent;
use Jose\Bundle\JoseFramework\Event\JWSVerificationFailureEvent;
use Jose\Bundle\JoseFramework\Event\JWSVerificationSuccessEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class JwsSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            Events::JWS_VERIFICATION_SUCCESS => ['onJwsVerificationSuccess'],
            Events::JWS_VERIFICATION_FAILURE => ['onJwsVerificationFailure'],
            Events::JWS_BUILT_SUCCESS => ['onJwsBuiltSuccess'],
            Events::JWS_BUILT_FAILURE => ['onJwsBuiltFailure'],
        ];
    }

    public function onJwsVerificationSuccess(JWSVerificationSuccessEvent $event): void
    {
        // Do something here
    }

    public function onJwsVerificationFailure(JWSVerificationFailureEvent $event): void
    {
        // Do something here
    }

    public function onJwsBuiltSuccess(JWSBuiltSuccessEvent $event): void
    {
        // Do something here
    }

    public function onJwsBuiltFailure(JWSBuiltFailureEvent $event): void
    {
        // Do something here
    }
}
```

{% endcode %}


# Profiling/Debugging


# Console

The project comes with console commands.\
They are available:

* [as a standalone command](/2.x/console-command/standalone)
* [through the dedicated Symfony console command](/2.x/console-command/symfony-console)
* [as a PHAR (PHP Archive)](/2.x/console-command/phar-application)

## Available Commands

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`.

You can save the output in a file e.g. when you want to store a key or keyset in your local filesystem.

```bash
./jose.phar key:convert:pkcs1 '{"kty":"EC","crv":"P-256","d":"kiNCxSbRjlAbHrEbrwVKS8vIXUh6URChrmw","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}' > key.pem
```

### Key Management Commands

#### Private Key To Public Key Converter

This command will convert a private key into a public key. It has no effect on shared keys (e.g. `oct` keys).

```bash
./jose.phar key:convert:public '{"kty":"EC","crv":"P-256","d":"kiNCxSbRjlAbHrEbrwVKS8vIXUh6URChrmw","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}'

{"kty":"EC","crv":"P-256","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}
```

#### Key Analyze

The following command will analyze the key passed as argument and find issues.

```bash
./jose.phar key:analyze '{"kty":"oct","k":"N2aIJSQCxTo"}'

The parameter "alg" should be added.
The parameter "use" should be added.
The parameter "kid" should be added.
The key length is less than 128 bits.
```

#### PKCS#1 Key Converter

This command will convert a RSA or EC key into PKCS#1 key.

```bash
./jose.phar key:convert:pkcs1 '{"kty":"EC","crv":"P-256","d":"kiNCxSbRjlAbHrEbrwVKS8vIXUh6URChrmw","x":"-wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgk","y":"rt8XDTalLMCRB5Tu9WQc2d0TOVwXXHkVDbI7cIig6r4"}'

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJIjQsUm0Y5QGx6xG68N4GrprVrFSkvLyF1IelEQoa5soAoGCCqGSM49
AwEHoUQDQgAE+wdLWDWCZP6oFYl8aGVfU0MsFlckjaSVrO7hEsc8lgmu3xcNNqUs
wJEHlO71ZBzZ3RM5XBdceRUNsjtwiKDqvg==
-----END EC PRIVATE KEY-----
```

#### Key Generators

The key generator commands will generate a private or shared key. The following options are available:

* `-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`.

```bash
./jose.phar key:generate:ec P-256

{"kty":"EC","crv":"P-256","d":"BZ231BFhhHAhx-D4myu4O1hi-vUHnRqxoCsQKUKFNrA","x":"Tv5YeQuD1CWDbfre65kYX2Lq_MGnUq0Ek2yUFixy31M","y":"pj0FyoGaByyBlt5RbTHhBdgcC-S6cgxzLpxd6mGmsbM"}
```

**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.

```bash
./jose.phar key:generate:rsa 512

{"kty":"RSA","n":"l1UPHqgOFThDUlfrP2DFnCwsD5ITls12nXer6A4YepUP_DnF9mFoXCkyflA_TOJtFiZW6NXWOY0NdE3YjzT-qQ","e":"AQAB","d":"CxVvxg8I-QTl6WIHGN09m_KgR4Ora6Agz-ez74sYv-GONPD3yjEWeAavdOsGK8iJX4Pe1Qss52VKddeKRQ9LAQ","p":"xkR0kbThGGD8HYtfPUv5Ds1zE5LlQvYgBiv15eOk9ns","q":"w2Xk86kiaRhXWXM8XPJ5Tn6bdTT6thzoqazuIO53SCs","dp":"RCBLibGEUvMoTiKQtChByRNRQl2MR2j48gXy9W42Rbc","dq":"T0x5910LxwUG5hl7ROluy6lcI9wFZ4Uh80JoPdspc5M","qi":"Z73ha9Fmg6s-rgRbF0dG0QMd1aY9g1i8qnAxXp3JMus"}
```

**Octet Key**

This command will generate a octet key (oct). Recommended size is 128 bits or more.

```bash
./jose.phar key:generate:oct 256

{"kty":"oct","k":"kWpZXidz3sVVx2Jn1J-5ANXnA2IKwfIAY2CoBW1q7I0"}
```

**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).

```bash
./jose.phar key:generate:okp 256

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**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.

```bash
./jose.phar key:generate:none

{"kty":"none","use":"sig","alg":"none"}
```

**From An Existing Secret**

If you already have a secret, you can use it to create an octet key (`oct`).

```bash
./jose.phar key:generate:from_secret "This is my secret"
```

In case your secret is binary string, you will have to encode it first (Base64) and indicate it is encoded.

```bash
./jose.phar key:generate:from_secret "VGhpcyBpcyBteSBzZWNyZXQ=" --is_b64
```

#### Key Loaders

The key loader commands will loader keys from various sources. The following options are available:

* `-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.

```bash
./jose.phar key:load:key /path/to/file.pem "This is my secret to decrypt the key"

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**Convert From PKCS#12 Keys**

This command can load and convert a PKCS#12 key file into a JWK. It supports encrypted keys.

```bash
./jose.phar key:load:p12 /path/to/file.p12 "This is my secret to decrypt the key"

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I","d":"BypCXV7KUai-zrwrdoAmgnHX6Kosw0sVpDVPwrXoNKY"}
```

**Convert From A X.509 Certificate**

This command can load and convert a X.509 key file into a JWK.

```bash
./jose.phar key:load:x509 /path/to/file.cert

{"kty":"OKP","crv":"X25519","x":"TgTD7RS0KF3eU8HdTM6ACxu365uco3x2Cee9SBXiu2I"}
```

#### RSA Key Optimization

This command optimizes a RSA key by calculating additional primes (CRT). The following option is available:

```bash
./jose.phar key:optimize '{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ"}'

{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ","p":"w0WuNlrO16rSPKHQn02FsOwzczlchC9ZpdS-00JKOr8","q":"xqn5LMfXwhWK-RGlXkSUHKCPb-SLKV8f8p41pDkjvvk","dp":"NGGAtfvt-FROSQ1vFQyKjEcQFhyRALRi6-UBu1HQ76k","dq":"kUqaO4_kUcNjogivwqOxFsauYIzq4dT6Dnx6iqJnbDE","qi":"TwJ4WOG0r1q6vZ13Kze2HPXtlnllyq9ZfClrVwovC_I"}
```

*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.*

#### Key Thumbprint

This command will calculate the key thumbprint as per the [RFC7638](https://tools.ietf.org/html/rfc7638). The following options are available:

* `--hash`: the hashing method. Default is `sha256`. Supported methods are the one listed by [`hash_algos`](http://php.net/manual/en/function.hash-algos.php).

```bash
./jose.phar key:thumbprint '{"kty":"RSA","n":"l4mLzvr6ewIWrPvP6j5PYp0yPRhtkMW1F-dbQ1VWGoB_Mq5IIuflOo7W2ERyh71exUGkmvoesWL3zCtFIOnlxw","e":"AQAB","d":"lxh8oLq7el9QwNasL0JF4WwgJa7vwISB1v3Gj9LM8cpZPqXnPGPeoE5QAOUi1bJsIEqzHsR-rnLHsarlTfXMIQ","p":"xqn5LMfXwhWK-RGlXkSUHKCPb-SLKV8f8p41pDkjvvk","q":"w0WuNlrO16rSPKHQn02FsOwzczlchC9ZpdS-00JKOr8","dp":"kUqaO4_kUcNjogivwqOxFsauYIzq4dT6Dnx6iqJnbDE","dq":"NGGAtfvt-FROSQ1vFQyKjEcQFhyRALRi6-UBu1HQ76k","qi":"dkguRXkQcrvYbvFcnmGrcjIs36FJa-1dtd7QCRYHTBo"}'

gNur2UtA8NMAoxJfgMYhJqnuWR8u-60aeRbKtZwj4DE
```

### Keyset Management Commands

#### Private Keys To Public Keys Converter

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).

```bash
./jose.phar keyset:convert:public '<keyset here>'

<public keyset>
```

#### Key Analyze

This command has the same behaviour as `key:analyze` except that it will analize all keys in the keyset.

```bash
./jose.phar keyset:analyze '<keyset here>'

<keyset analyze result>
```

#### Keyset Generators

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:

```bash
./jose.phar keyset:generate:rsa 3 512 # Create 3 RSA keys (512 bits each)
./jose.phar keyset:generate:oct 5 128 # Create 5 oct keys (128 bits each)
./jose.phar keyset:generate:okp 2 X25519 # Create 2 OKP keys (curve X25519)
./jose.phar keyset:generate:ec 3 P-521 # Create 3 EC keys (curve P-521)
```

The result of these commands is a JWKSet object.

#### Key Set Modification

* `keyset:add:key`:         Add a key into a key set.
* `keyset:merge`:           Merge several key sets into one.
* `keyset:rotate`:          Rotate a key set.

#### Distant Key Set Loading

* `keyset:load:jku`:        Loads a key set from an url.
* `keyset:load:x5u`:        Loads a key set from an url.


# Standalone Application

## Installation

To install the standalone application, you have to clone the repository and install the dependencies.\
We consider that `git` and `composer` are correctly installed.

```bash
git clone https://github.com/web-token/jwt-app.git
cd jwt-app
composer install --no-dev --optimize-autoloader --classmap-authoritative
```

You will find the standalone console command in the `bin` folder.

```bash
./bin/jose
```


# PHAR Application

## Installation

To install the application, you just have to download it and download the associated public key (the application is digitally signed):

```bash
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey
```

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:

```bash
./jose.phar
```

## Update

The application can be updated easily:

```bash
./jose.phar selfupdate
```

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:

```bash
./jose.phar rollback
```


# Symfony Console

To enable the commands on a Symfony application, you have to install and add the associated bundle into your kernel:

```bash
composer require web-token/jwt-console
composer require web-token/jwt-bundle
```

If you use Symfony Flex, you have nothing to do. Otherwise you have to enable to bundle.

```php
// app/AppKernel.php

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            ...
            new Jose\Bundle\JwtFramework\JwtFrameworkBundle(),
        ];

        return $bundles;
    }
    ...
}
```

Then execute your Symfony Console command to use the command provided by this component:

```bash
./bin/console
```




---

[Next Page](/llms-full.txt/1)

