Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 119 additions & 9 deletions advanced/nested_tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,125 @@ Nested Tokens
=============

JWT can be signed or encrypted and both operations can be performed when you needed.
This library is able to create and load nested tokens, but at the moment there is no build in class to do that.
This library is able to create and load nested tokens using dedicated classes.

There are few recommendations to follow when you want to deal with nested tokens:
The `NestedTokenLoader` and `NestedTokenBuilder` classes are available when the `web-token/jwt-encryption` component is installed.
However, you must also install the following component to use it:

1. You have to set the following header parameters. These headers indicate that the token contains another token.
* `typ`: `JWT`,
* `cty`: `JWT`.
2. The token MUST first be signed, then encrypted
* `web-token/jwt-checker`
* `web-token/jwt-signature`

**The order is very important**.
If you first encrypt then you sign, the signature can be removed in favour of another one using a weaker algorithm are a corrupted key.
Moreover, it protects the signer privacy by hiding information that could be set in the JWS header.
# Nested Token Loading

To instantiate the `NestedTokenLoader`, you just 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 used to verify the signed token.
You should use this variable if the returned `JWS` object contains more than one signature.

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

# Nested Token Building

To instantiate the `NestedTokenBuilderder`, you will need a `JWSBuilder`, a `JWEBuilder`, a `JWESerializerManager` and 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 remainder, 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.

```yaml

class AcmeExtension extends Extension implements PrependExtensionInterface
{
...

/**
* {@inheritdoc}
*/
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, []);
}
}
```