Migrating from python-jose
==========================

``python-jose`` supports all JOSE specifications, similar to ``joserfc``.
However, there are significant differences in code structure, method names,
and parameter usage. Additionally, ``joserfc`` offers built-in Python type
hints, enhancing code readability and type safety.

Another key difference is that ``python-jose`` only supports compact serialization
and deserialization, whereas ``joserfc`` supports both compact and JSON serialization
formats, offering greater flexibility in handling JOSE data.

JWS
---

In ``python-jose``, the methods used for serialization and deserialization are
``jws.sign`` and ``jws.verify``, respectively.

On the other hand, ``joserfc`` uses ``jws.serialize_compact`` for serialization
and ``jws.deserialize_compact`` for deserialization.

.. code-block:: python
    :caption: python-jose

    from jose import jws

    signed = jws.sign({'a': 'b'}, 'your-secret-key', algorithm='HS256')
    jws.verify(signed, 'your-secret-key', algorithms='HS256')
    # the verify only returns the payload

.. code-block:: python
    :caption: joserfc

    import json
    from joserfc import jws
    from joserfc.jwk import OctKey

    key = OctKey.import_key("your-secret-key")
    protected = {"alg": "HS256"}
    signed = jws.serialize_compact(protected, json.dumps({'a': 'b'}), key)
    obj = jws.deserialize_compact(text, key)
    # access the payload with obj.payload

.. important::

    ``joserfc`` is designed to be highly explicit, requiring the use of specific
    key types, payload formats, and other components. For example, in the previous
    example, we explicitly use an OctKey instead of a simple string. Additionally,
    since JWS in joserfc only supports encoding strings and bytes, you cannot pass
    a dictionary directly as the payload. Instead, the payload must first be converted
    to a JSON string using json.dumps. This explicit approach ensures better type
    safety and clarity in your code.

JWE
---

In ``python-jose``, the methods used for encryption and decryption are ``jwe.encrypt``
and ``jwe.decrypt``. However, since ``joserfc`` supports both compact and JSON serialization
formats, it provides distinct methods: ``jwe.encrypt_compact`` and ``jwe.decrypt_compact`` for
compact serialization, ensuring clear differentiation between the formats and greater
flexibility in handling JWE operations.

.. code-block:: python
    :caption: python-jose

    from jose import jwe

    encrypted = jwe.encrypt('Hello, World!', 'asecret128bitkey', algorithm='dir', encryption='A128GCM')
    jwe.decrypt(encrypted, 'asecret128bitkey')
    # => 'Hello, World!'

.. code-block:: python
    :caption: joserfc

    from joserfc import jwe
    from joserfc.jwk import OctKey

    key = OctKey.generate_key(128)  # 128bit key
    protected = {'alg': 'dir', 'enc': 'A128GCM'}
    encrypted = jwe.encrypt_compact(protected, 'Hello, World!', key)
    obj = jwe.decrypt_compact(encrypted, key)
    # obj.payload => b'Hello, World!'

JWT
---

The ``jwt`` module in ``python-jose`` supports only JWS (JSON Web Signature) mode,
whereas ``joserfc`` provides support for both JWS and JWE (JSON Web Encryption) modes.
Although both libraries utilize the ``encode`` and ``decode`` methods, their parameters
differ significantly in terms of structure and flexibility.

.. code-block:: python
    :caption: python-jose

    from jose import jwt

    encoded = jwt.encode({'a': 'b'}, 'your-secret-key', algorithm='HS256')
    jwt.decode(encoded, 'your-secret-key', algorithms='HS256')
    # => {'a': 'b'}

.. code-block:: python
    :caption: joserfc

    from joserfc import jwt
    from joserfc.jwk import OctKey

    key = OctKey.import_key("your-secret-key")
    # jwt.encode(header, payload, key)
    encoded = jwt.encode({"alg": "HS256"}, {'a': 'b'}, key)
    token = jwt.decode(encoded, key)
    # => token.header : {"alg": "HS256"}
    # => token.claims : {"a": "b"}

.. warning::

    ``python-jose`` will automatically convert and validate string values for JWT claims
    (e.g. `exp`, `iat` and `nbf`) whereas ``joserfc`` will raise an exception when
    using the `JWTClaimsRegistry`.

``get_unverified_header``
~~~~~~~~~~~~~~~~~~~~~~~~~

The ``jwt`` module in python-jose provides a method called ``get_unverified_header``,
which allows extracting the header from a JWT without verifying its signature.

In ``joserfc``, we can get the unverified header with:

.. code-block:: python
    :caption: joserfc

    from typing import Any
    from joserfc import jws

    def get_unverified_header(token: str) -> dict[str, Any]:
        obj = jws.extract_compact(token.encode())
        return obj.protected

``get_unverified_claims``
~~~~~~~~~~~~~~~~~~~~~~~~~

You can also use the ``jws.extract_compact`` method to extract the JWT's claims:

.. code-block:: python
    :caption: joserfc

    import json
    from typing import Any
    from joserfc import jws

    def get_unverified_claims(token: str) -> dict[str, Any]:
        obj = jws.extract_compact(token.encode())
        return json.loads(obj.payload)

JWK
---

In ``python-jose``, you can use ``jwk.construct`` to create a key instance
from a JWK-formatted dictionary. In contrast, ``joserfc`` provides the
``jwk.import_key`` method to achieve the same result.

.. code-block:: python
    :caption: joserfc

    from joserfc import jwk

    jwk.import_key({
        "kty": "oct",
        "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037",
        "use": "sig",
        "alg": "HS256",
        "k": "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg"
    })
