1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
:description: Advanced usage of registry for JWS, and JWE.
.. _registry:
Registry
========
.. module:: joserfc
:noindex:
The ``registry`` is specifically designed to store supported algorithms,
allowed algorithms, registered header parameters, and provides methods
to validate algorithms and headers.
.. note::
We'll use ``JWSRegistry`` as our reference, but keep in mind that
the behavior of ``JWERegistry`` is identical.
Algorithms
----------
The ``JWSRegistry`` or ``JWERegistry`` serves as a storage for all supported
algorithms in JWS or JWE. By default, it enforces the usage of recommended
algorithms, ensuring a higher level of security.
Find all the supported and recommended algorithms in:
- :ref:`jws_algorithms`
- :ref:`jwe_algorithms`
You have the flexibility to create a custom registry tailored to your specific
program requirements, allowing you to define and restrict the algorithms used.
For instance, you can design a custom JWS registry that only permits the usage
of ``RS256`` and ``ES256`` algorithms. This ensures that only these specific
algorithms are allowed in your program.
.. code-block:: python
from joserfc.jws import JWSRegistry
registry = JWSRegistry(algorithms=["RS256", "ES256"])
# jws.serialize_compact(protected, payload, key, registry=registry)
An example of a custom JWE registry that only permits the usage of
``{"alg": "A128KW", "enc": "A128GCM"}``:
.. code-block:: python
from joserfc.jwe import JWERegistry
registry = JWERegistry(algorithms=["A128KW", "A128GCM"])
# jwe.encrypt_compact(protected, payload, key, registry=registry)
Headers
-------
By default, the ``JWSRegistry`` only permits the usage of registered header
parameters. Additionally, it verifies the validity of the header parameter
values before allowing their usage.
Type checking
~~~~~~~~~~~~~
The header parameter registry for JWS and JWE performs an initial check on
the value type.
.. code-block:: python
>>> from joserfc import jws
>>> from joserfc.jwk import OctKey
>>> key = OctKey.import_key("your-secret-key")
>>> jws.serialize_compact({"alg": "HS256", "kid": 123}, "hello", key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../joserfc/jws.py", line 111, in serialize_compact
registry.check_header(protected)
File ".../joserfc/rfc7515/registry.py", line 68, in check_header
validate_registry_header(self.header_registry, header)
File ".../joserfc/registry.py", line 194, in validate_registry_header
raise InvalidHeaderValueError(f"'{key}' in header {error}")
joserfc.errors.InvalidHeaderValueError: invalid_header_value: 'kid' in header must be a str
In the above example, ``kid`` MUST be a string instead of an integer. The default
registry validates the ``kid`` before processing the serialization.
Critical headers
~~~~~~~~~~~~~~~~
There is a special "crit" header parameter for JWS and JWE, which specifies
the critical header parameters. These critical parameters are considered mandatory,
indicating that they must be present. For example:
.. code-block:: python
>>> from joserfc import jws
>>> from joserfc.jwk import OctKey
>>> key = OctKey.import_key("your-secret-key")
>>> jws.serialize_compact({"alg": "HS256", "crit": ["kid"]}, "hello", key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../joserfc/jws.py", line 111, in serialize_compact
registry.check_header(protected)
File ".../joserfc/rfc7515/registry.py", line 67, in check_header
check_crit_header(header)
File ".../joserfc/registry.py", line 202, in check_crit_header
raise MissingCritHeaderError(k)
joserfc.errors.MissingCritHeaderError: missing_crit_header: Missing critical 'kid' value in header
Since "kid" is listed as a critical (``crit``) header parameter, it is mandatory
and must be included in the header.
Additional headers
~~~~~~~~~~~~~~~~~~
By default, the registry for JWS and JWE only permits registered header parameters.
Any additional header beyond those supported by the algorithm will result in an error.
.. code-block:: python
>>> from joserfc import jws
>>> from joserfc.jwk import OctKey
>>> key = OctKey.import_key("your-secret-key")
>>> jws.serialize_compact({"alg": "HS256", "custom": "hi"}, "hello", key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../joserfc/jws.py", line 111, in serialize_compact
registry.check_header(protected)
File ".../joserfc/rfc7515/registry.py", line 70, in check_header
check_supported_header(self.header_registry, header)
File ".../joserfc/registry.py", line 183, in check_supported_header
raise UnsupportedHeaderError(f"Unsupported {unsupported_keys} in header")
joserfc.errors.UnsupportedHeaderError: unsupported_header: Unsupported {'custom'} in header
To resolve this error, you have two options. First, you can register the
additional header parameters with the registry. This allows the registry
to recognize and validate those parameters instead of raising an error.
.. code-block:: python
from joserfc import jws
from joserfc.jws import JWSRegistry
from joserfc.registry import HeaderParameter
from joserfc.jwk import OctKey
key = OctKey.import_key("your-secret-key")
additional_header_registry = {
"custom": HeaderParameter("Custom message", "str", required=True),
}
registry = JWSRegistry(additional_header_registry)
# it will not raise any error
jws.serialize_compact({"alg": "HS256", "custom": "hi"}, "hello", key, registry=registry)
# this will raise an error, because we "custom" is defined to be required
jws.serialize_compact({"alg": "HS256"}, "hello", key, registry=registry)
Alternatively, you can choose to disable the strict header checking altogether.
By turning off strict header checking, the registry will no longer raise an
error for unrecognized header parameters. However, please note that this approach
may compromise the security and integrity of the token, so it should be used with caution.
.. code-block:: python
registry = JWSRegistry(strict_check_header=False)
# will not raise any error
jws.serialize_compact({"alg": "HS256", "custom": "hi"}, "hello", key, registry=registry)
Registry for JWT
----------------
JSON Web Token (JWT) is built on top of :ref:`jws` or :ref:`jwe`. The ``encode`` and ``decode``
methods accept a ``registry`` parameter. Depending on the algorithm of the JWT, you need to
decide whether to use ``JWSRegistry`` or ``JWERegistry``.
|