pub_key = algo.prepare_key(keyfile.read())

        result = algo.verify(message, pub_key, sig)
        assert not result

    @crypto_required
    def test_ec_should_throw_exception_on_wrong_key(self):
        algo = ECAlgorithm(ECAlgorithm.SHA256)

        with pytest.raises(InvalidKeyError):
            with open(key_path("testkey_rsa.priv")) as keyfile:
                algo.prepare_key(keyfile.read())

        with pytest.raises(InvalidKeyError):
            with open(key_path("testkey2_rsa.pub.pem")) as pem_key:
                algo.prepare_key(pem_key.read())

    @crypto_required
    def test_rsa_pss_sign_then_verify_should_return_true(self):
        algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256)

        message = b"Hello World!"

        with open(key_path("testkey_rsa.priv")) as keyfile:
            priv_key = cast(RSAPrivateKey, algo.prepare_key(keyfile.read()))
            sig = algo.sign(message, priv_key)

        with open(key_path("testkey_rsa.pub")) as keyfile:
            pub_key = cast(RSAPublicKey, algo.prepare_key(keyfile.read()))

        result = algo.verify(message, pub_key, sig)
        assert result

    @crypto_required
    def test_rsa_pss_verify_should_return_false_if_signature_invalid(self):
        algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256)

        jwt_message = b"Hello World!"

        jwt_sig = base64.b64decode(
            b"ywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNu"
            b"vQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c"
            b"/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk"
            b"186/LopP4xe5c/hxOQjwhv6yDlTiwJFiqjNCvj0GyBKsc4iECLGIIO+4mC4"
            b"daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5"
            b"drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg=="
        )

        jwt_sig += b"123"  # Signature is now invalid

        with open(key_path("testkey_rsa.pub")) as keyfile:
            jwt_pub_key = cast(RSAPublicKey, algo.prepare_key(keyfile.read()))

        result = algo.verify(jwt_message, jwt_pub_key, jwt_sig)
        assert not result


class TestAlgorithmsRFC7520:
    """
    These test vectors were taken from RFC 7520
    (https://tools.ietf.org/html/rfc7520)
    """

    def test_hmac_verify_should_return_true_for_test_vector(self):
        """
        This test verifies that HMAC verification works with a known good
        signature and key.

        Reference: https://tools.ietf.org/html/rfc7520#section-4.4
        """
        signing_input = (
    def test_bytes_secret(self, jws, payload):
        secret = b"\xc2"  # char value that ascii codec cannot decode
        jws_message = jws.encode(payload, secret)

        decoded_payload = jws.decode(jws_message, secret, algorithms=["HS256"])

        assert decoded_payload == payload

    @pytest.mark.parametrize("sort_headers", (False, True))
    def test_sorting_of_headers(self, jws, payload, sort_headers):
        jws_message = jws.encode(
            payload,
            key="\xc2",
            headers={"b": "1", "a": "2"},
            sort_headers=sort_headers,
        )
        header_json = base64url_decode(jws_message.split(".")[0])
        assert sort_headers == (header_json.index(b'"a"') < header_json.index(b'"b"'))

    def test_decode_invalid_header_padding(self, jws):
        example_jws = (
            "aeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            ".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            ".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        example_secret = "secret"

        with pytest.raises(DecodeError) as exc:
            jws.decode(example_jws, example_secret, algorithms=["HS256"])

        assert "header padding" in str(exc.value)

    def test_decode_invalid_header_string(self, jws):
        example_jws = (
            "eyJhbGciOiAiSFMyNTbpIiwgInR5cCI6ICJKV1QifQ=="
            ".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            ".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        example_secret = "secret"

        with pytest.raises(DecodeError) as exc:
            jws.decode(example_jws, example_secret, algorithms=["HS256"])

        assert "Invalid header" in str(exc.value)

    def test_decode_invalid_payload_padding(self, jws):
        example_jws = (
            "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            ".aeyJoZWxsbyI6ICJ3b3JsZCJ9"
            ".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        example_secret = "secret"

        with pytest.raises(DecodeError) as exc:
            jws.decode(example_jws, example_secret, algorithms=["HS256"])

        assert "Invalid payload padding" in str(exc.value)

    def test_decode_invalid_crypto_padding(self, jws):
        example_jws = (
            "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            ".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            ".aatvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        example_secret = "secret"

        with pytest.raises(DecodeError) as exc:
            jws.decode(example_jws, example_secret, algorithms=["HS256"])

        assert "Invalid crypto padding" in str(exc.value)

    def test_decode_with_algo_none_should_fail(self, jws, payload):
        jws_message = jws.encode(payload, key=None, algorithm=None)

        with pytest.raises(DecodeError):
            jws.decode(jws_message, algorithms=["none"])

    def test_decode_with_algo_none_and_verify_false_should_pass(self, jws, payload):
        jws_message = jws.encode(payload, key=None, algorithm=None)
        jws.decode(jws_message, options={"verify_signature": False})

    def test_get_unverified_header_returns_header_values(self, jws, payload):
        jws_message = jws.encode(
            payload,
            key="secret",
            algorithm="HS256",
            headers={"kid": "toomanysecrets"},
        )

        header = jws.get_unverified_header(jws_message)

        assert "kid" in header
        assert header["kid"] == "toomanysecrets"

    def test_get_unverified_header_fails_on_bad_header_types(self, jws, payload):
        # Contains a bad kid value (int 123 instead of string)
        example_jws = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MTIzfQ"
            ".eyJzdWIiOiIxMjM0NTY3ODkwIn0"
            ".vs2WY54jfpKP3JGC73Vq5YlMsqM5oTZ1ZydT77SiZSk"
        )

        with pytest.raises(InvalidTokenError) as exc:
            jws.get_unverified_header(example_jws)

        assert "Key ID header parameter must be a string" == str(exc.value)

    @pytest.mark.parametrize(
        "algo",
        [
            "RS256",
            "RS384",
            "RS512",
        ],
    )
    @crypto_required
    def test_encode_decode_rsa_related_algorithms(self, jws, payload, algo):
        # PEM-formatted RSA key
        with open(key_path("testkey_rsa.priv"), "rb") as rsa_priv_file:
            priv_rsakey = load_pem_private_key(rsa_priv_file.read(), password=None)
            jws_message = jws.encode(payload, priv_rsakey, algorithm=algo)

        with open(key_path("testkey_rsa.pub"), "rb") as rsa_pub_file:
            pub_rsakey = load_ssh_public_key(rsa_pub_file.read())
            jws.decode(jws_message, pub_rsakey, algorithms=[algo])

        # string-formatted key
        with open(key_path("testkey_rsa.priv")) as rsa_priv_file:
            priv_rsakey = rsa_priv_file.read()  # type: ignore[assignment]
            jws_message = jws.encode(payload, priv_rsakey, algorithm=algo)

        with open(key_path("testkey_rsa.pub")) as rsa_pub_file:
            pub_rsakey = rsa_pub_file.read()  # type: ignore[assignment]
            jws.decode(jws_message, pub_rsakey, algorithms=[algo])

    def test_rsa_related_algorithms(self, jws):
        jws = PyJWS()
        jws_algorithms = jws.get_algorithms()

        if has_crypto:
            assert "RS256" in jws_algorithms
            assert "RS384" in jws_algorithms
            assert "RS512" in jws_algorithms
            assert "PS256" in jws_algorithms
            assert "PS384" in jws_algorithms
            assert "PS512" in jws_algorithms

        else:
            assert "RS256" not in jws_algorithms
            assert "RS384" not in jws_algorithms
            assert "RS512" not in jws_algorithms
            assert "PS256" not in jws_algorithms
            assert "PS384" not in jws_algorithms
            assert "PS512" not in jws_algorithms

    @pytest.mark.parametrize(
        "algo",
        [
            "ES256",
            "ES256K",
            "ES384",
            "ES512",
        ],
    )
    @crypto_required
    def test_encode_decode_ecdsa_related_algorithms(self, jws, payload, algo):
        # PEM-formatted EC key
        with open(key_path("testkey_ec.priv"), "rb") as ec_priv_file:
            priv_eckey = load_pem_private_key(ec_priv_file.read(), password=None)
            jws_message = jws.encode(payload, priv_eckey, algorithm=algo)

        with open(key_path("testkey_ec.pub"), "rb") as ec_pub_file:
            pub_eckey = load_pem_public_key(ec_pub_file.read())
            jws.decode(jws_message, pub_eckey, algorithms=[algo])

        # string-formatted key
        with open(key_path("testkey_ec.priv")) as ec_priv_file:
            priv_eckey = ec_priv_file.read()  # type: ignore[assignment]
            jws_message = jws.encode(payload, priv_eckey, algorithm=algo)

        with open(key_path("testkey_ec.pub")) as ec_pub_file:
            pub_eckey = ec_pub_file.read()  # type: ignore[assignment]
            jws.decode(jws_message, pub_eckey, algorithms=[algo])

    def test_ecdsa_related_algorithms(self, jws):
        jws = PyJWS()
        jws_algorithms = jws.get_algorithms()

        if has_crypto:
            assert "ES256" in jws_algorithms
            assert "ES256K" in jws_algorithms
            assert "ES384" in jws_algorithms
            assert "ES512" in jws_algorithms
        else:
            assert "ES256" not in jws_algorithms
            assert "ES256K" not in jws_algorithms
            assert "ES384" not in jws_algorithms
            assert "ES512" not in jws_algorithms

    def test_skip_check_signature(self, jws):
        token = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
            ".eyJzb21lIjoicGF5bG9hZCJ9"
            ".4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZA"
        )
        jws.decode(token, "secret", options={"verify_signature": False})

    def test_decode_options_must_be_dict(self, jws, payload):
        token = jws.encode(payload, "secret")

        with pytest.raises(TypeError):
            jws.decode(token, "secret", options=object())

        with pytest.raises((TypeError, ValueError)):
            jws.decode(token, "secret", options="something")

    def test_custom_json_encoder(self, jws, payload):
        class CustomJSONEncoder(json.JSONEncoder):
            def default(self, o):
                if isinstance(o, Decimal):
                    return "it worked"
                return super().default(o)

        data = {"some_decimal": Decimal("2.2")}

        with pytest.raises(TypeError):
            jws.encode(payload, "secret", headers=data)

        token = jws.encode(
            payload, "secret", headers=data, json_encoder=CustomJSONEncoder
        )

        header, *_ = token.split(".")
        header = json.loads(base64url_decode(header))

        assert "some_decimal" in header
        assert header["some_decimal"] == "it worked"

    def test_encode_headers_parameter_adds_headers(self, jws, payload):
        headers = {"testheader": True}
        token = jws.encode(payload, "secret", headers=headers)

        if not isinstance(token, str):
            token = token.decode()

        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)

        if not isinstance(header, str):
            header = header.decode()

        header_obj = json.loads(header)

        assert "testheader" in header_obj
        assert header_obj["testheader"] == headers["testheader"]

    def test_encode_with_typ(self, jws):
        payload = """
        {
          "iss": "https://scim.example.com",
          "iat": 1458496404,
          "jti": "4d3559ec67504aaba65d40b0363faad8",
          "aud": [
            "https://scim.example.com/Feeds/98d52461fa5bbc879593b7754",
            "https://scim.example.com/Feeds/5d7604516b1d08641d7676ee7"
          ],
          "events": {
            "urn:ietf:params:scim:event:create": {
              "ref":
                  "https://scim.example.com/Users/44f6142df96bd6ab61e7521d9",
              "attributes": ["id", "name", "userName", "password", "emails"]
            }
          }
        }
        """
        token = jws.encode(
            payload.encode("utf-8"), "secret", headers={"typ": "secevent+jwt"}
        )

        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)
        header_obj = json.loads(header)

        assert "typ" in header_obj
        assert header_obj["typ"] == "secevent+jwt"

    def test_encode_with_typ_empty_string(self, jws, payload):
        token = jws.encode(payload, "secret", headers={"typ": ""})

        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)
        header_obj = json.loads(header)

        assert "typ" not in header_obj

    def test_encode_with_typ_none(self, jws, payload):
        token = jws.encode(payload, "secret", headers={"typ": None})

        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)
        header_obj = json.loads(header)

        assert "typ" not in header_obj

    def test_encode_with_typ_without_keywords(self, jws, payload):
        headers = {"foo": "bar"}
        token = jws.encode(payload, "secret", "HS256", headers, None)

        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)
        header_obj = json.loads(header)

        assert "foo" in header_obj
        assert header_obj["foo"] == "bar"

    def test_encode_fails_on_invalid_kid_types(self, jws, payload):
        with pytest.raises(InvalidTokenError) as exc:
            jws.encode(payload, "secret", headers={"kid": 123})

        assert "Key ID header parameter must be a string" == str(exc.value)

        with pytest.raises(InvalidTokenError) as exc:
            jws.encode(payload, "secret", headers={"kid": None})

        assert "Key ID header parameter must be a string" == str(exc.value)

    def test_encode_decode_with_detached_content(self, jws, payload):
        secret = "secret"
        jws_message = jws.encode(
            payload, secret, algorithm="HS256", is_payload_detached=True
        )

        jws.decode(jws_message, secret, algorithms=["HS256"], detached_payload=payload)

    def test_encode_detached_content_with_b64_header(self, jws, payload):
        secret = "secret"

        # Check that detached content is automatically detected when b64 is false
        headers = {"b64": False}<response clipped><NOTE>Due to the max output limit, only part of the full response has been shown to you.</NOTE>            secret,
                algorithms=["HS256"],
                detached_payload=payload,
                foo="bar",
            )
        assert len(record) == 1
        assert "foo" in str(record[0].message)
import json
import time
from calendar import timegm
from datetime import datetime, timedelta, timezone
from decimal import Decimal

import pytest

from jwt.api_jwt import PyJWT
from jwt.exceptions import (
    DecodeError,
    ExpiredSignatureError,
    ImmatureSignatureError,
    InvalidAudienceError,
    InvalidIssuedAtError,
    InvalidIssuerError,
    MissingRequiredClaimError,
)
from jwt.utils import base64url_decode
from jwt.warnings import RemovedInPyjwt3Warning

from .utils import crypto_required, key_path, utc_timestamp


@pytest.fixture
def jwt():
    return PyJWT()


@pytest.fixture
def payload():
    """Creates a sample JWT claimset for use as a payload during tests"""
    return {"iss": "jeff", "exp": utc_timestamp() + 15, "claim": "insanity"}


class TestJWT:
    def test_decodes_valid_jwt(self, jwt):
        example_payload = {"hello": "world"}
        example_secret = "secret"
        example_jwt = (
            b"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            b".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        decoded_payload = jwt.decode(example_jwt, example_secret, algorithms=["HS256"])

        assert decoded_payload == example_payload

    def test_decodes_complete_valid_jwt(self, jwt):
        example_payload = {"hello": "world"}
        example_secret = "secret"
        example_jwt = (
            b"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            b".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )
        decoded = jwt.decode_complete(example_jwt, example_secret, algorithms=["HS256"])

        assert decoded == {
            "header": {"alg": "HS256", "typ": "JWT"},
            "payload": example_payload,
            "signature": (
                b'\xb6\xf6\xa0,2\xe8j"J\xc4\xe2\xaa\xa4\x15\xd2'
                b"\x10l\xbbI\x84\xa2}\x98c\x9e\xd8&\xf5\xcbi\xca?"
            ),
        }

    def test_load_verify_valid_jwt(self, jwt):
        example_payload = {"hello": "world"}
        example_secret = "secret"
        example_jwt = (
            b"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            b".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            b".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )

        decoded_payload = jwt.decode(
            example_jwt, key=example_secret, algorithms=["HS256"]
        )

        assert decoded_payload == example_payload

    def test_decode_invalid_payload_string(self, jwt):
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aGVsb"
            "G8gd29ybGQ.SIr03zM64awWRdPrAM_61QWsZchAtgDV"
            "3pphfHPPWkI"
        )
        example_secret = "secret"

        with pytest.raises(DecodeError) as exc:
            jwt.decode(example_jwt, example_secret, algorithms=["HS256"])

        assert "Invalid payload string" in str(exc.value)

    def test_decode_with_non_mapping_payload_throws_exception(self, jwt):
        secret = "secret"
        example_jwt = (
            "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9."
            "MQ."  # == 1
            "AbcSR3DWum91KOgfKxUHm78rLs_DrrZ1CrDgpUFFzls"
        )

        with pytest.raises(DecodeError) as context:
            jwt.decode(example_jwt, secret, algorithms=["HS256"])

        exception = context.value
        assert str(exception) == "Invalid payload string: must be a json object"

    def test_decode_with_invalid_audience_param_throws_exception(self, jwt):
        secret = "secret"
        example_jwt = (
            "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
            ".eyJoZWxsbyI6ICJ3b3JsZCJ9"
            ".tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8"
        )

        with pytest.raises(TypeError) as context:
            jwt.decode(example_jwt, secret, audience=1, algorithms=["HS256"])

        exception = context.value
        assert str(exception) == "audience must be a string, iterable or None"

    def test_decode_with_nonlist_aud_claim_throws_exception(self, jwt):
        secret = "secret"
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
            ".eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoxfQ"  # aud = 1
            ".Rof08LBSwbm8Z_bhA2N3DFY-utZR1Gi9rbIS5Zthnnc"
        )

        with pytest.raises(InvalidAudienceError) as context:
            jwt.decode(
                example_jwt,
                secret,
                audience="my_audience",
                algorithms=["HS256"],
            )

        exception = context.value
        assert str(exception) == "Invalid claim format in token"

    def test_decode_with_invalid_aud_list_member_throws_exception(self, jwt):
        secret = "secret"
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
            ".eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbMV19"
            ".iQgKpJ8shetwNMIosNXWBPFB057c2BHs-8t1d2CCM2A"
        )

        with pytest.raises(InvalidAudienceError) as context:
            jwt.decode(
                example_jwt,
                secret,
                audience="my_audience",
                algorithms=["HS256"],
            )

        exception = context.value
        assert str(exception) == "Invalid claim format in token"

    def test_encode_bad_type(self, jwt):
        types = ["string", tuple(), list(), 42, set()]

        for t in types:
            pytest.raises(
                TypeError,
                lambda: jwt.encode(t, "secret", algorithms=["HS256"]),
            )

    def test_encode_with_typ(self, jwt):
        payload = {
            "iss": "https://scim.example.com",
            "iat": 1458496404,
            "jti": "4d3559ec67504aaba65d40b0363faad8",
            "aud": [
                "https://scim.example.com/Feeds/98d52461fa5bbc879593b7754",
                "https://scim.example.com/Feeds/5d7604516b1d08641d7676ee7",
            ],
            "events": {
                "urn:ietf:params:scim:event:create": {
                    "ref": "https://scim.example.com/Users/44f6142df96bd6ab61e7521d9",
                    "attributes": ["id", "name", "userName", "password", "emails"],
                }
            },
        }
        token = jwt.encode(
            payload, "secret", algorithm="HS256", headers={"typ": "secevent+jwt"}
        )
        header = token[0 : token.index(".")].encode()
        header = base64url_decode(header)
        header_obj = json.loads(header)

        assert "typ" in header_obj
        assert header_obj["typ"] == "secevent+jwt"

    def test_decode_raises_exception_if_exp_is_not_int(self, jwt):
        # >>> jwt.encode({'exp': 'not-an-int'}, 'secret')
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
            "eyJleHAiOiJub3QtYW4taW50In0."
            "P65iYgoHtBqB07PMtBSuKNUEIPPPfmjfJG217cEE66s"
        )

        with pytest.raises(DecodeError) as exc:
            jwt.decode(example_jwt, "secret", algorithms=["HS256"])

        assert "exp" in str(exc.value)

    def test_decode_raises_exception_if_iat_is_not_int(self, jwt):
        # >>> jwt.encode({'iat': 'not-an-int'}, 'secret')
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
            "eyJpYXQiOiJub3QtYW4taW50In0."
            "H1GmcQgSySa5LOKYbzGm--b1OmRbHFkyk8pq811FzZM"
        )

        with pytest.raises(InvalidIssuedAtError):
            jwt.decode(example_jwt, "secret", algorithms=["HS256"])


    def test_decode_raises_exception_if_iat_is_greater_than_now(self, jwt, payload):
        payload["iat"] = utc_timestamp() + 10
        secret = "secret"
        jwt_message = jwt.encode(payload, secret)

        with pytest.raises(ImmatureSignatureError):
            jwt.decode(jwt_message, secret, algorithms=["HS256"])

    def test_decode_works_if_iat_is_str_of_a_number(self, jwt, payload):
        payload["iat"] = "1638202770"
        secret = "secret"
        jwt_message = jwt.encode(payload, secret)
        data = jwt.decode(jwt_message, secret, algorithms=["HS256"])
        assert data["iat"] == "1638202770"

    def test_decode_raises_exception_if_nbf_is_not_int(self, jwt):
        # >>> jwt.encode({'nbf': 'not-an-int'}, 'secret')
        example_jwt = (
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
            "eyJuYmYiOiJub3QtYW4taW50In0."
            "c25hldC8G2ZamC8uKpax9sYMTgdZo3cxrmzFHaAAluw"
        )

        with pytest.raises(DecodeError):
            jwt.decode(example_jwt, "secret", algorithms=["HS256"])

    def test_decode_raises_exception_if_aud_is_none(self, jwt):
        # >>> jwt.encode({'aud': None}, 'secret')
        example_jwt = (
            "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9."
            "eyJhdWQiOm51bGx9."
            "-Peqc-pTugGvrc5C8Bnl0-X1V_5fv-aVb_7y7nGBVvQ"
        )
        decoded = jwt.decode(example_jwt, "secret", algorithms=["HS256"])
        assert decoded["aud"] is None

    def test_encode_datetime(self, jwt):
        secret = "secret"
        current_datetime = datetime.now(tz=timezone.utc)
        payload = {
            "exp": current_datetime,
            "iat": current_datetime,
            "nbf": current_datetime,
        }
        jwt_message = jwt.encode(payload, secret)
        decoded_payload = jwt.decode(
            jwt_message, secret, leeway=1, algorithms=["HS256"]
        )

        assert decoded_payload["exp"] == timegm(current_datetime.utctimetuple())
        assert decoded_payload["iat"] == timegm(current_datetime.utctimetuple())
        assert decoded_payload["nbf"] == timegm(current_datetime.utctimetuple())
        # payload is not mutated.
        assert payload == {
            "exp": current_datetime,
            "iat": current_datetime,
            "nbf": current_datetime,
        }

    # 'Control' Elliptic Curve JWT created by another library.
    # Used to test for regressions that could affect both
    # encoding / decoding operations equally (causing tests
    # to still pass).
    @crypto_required
    def test_decodes_valid_es256_jwt(self, jwt):
        example_payload = {"hello": "world"}
        with open(key_path("testkey_ec.pub")) as fp:
            example_pubkey = fp.read()
        example_jwt = (
            b"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9."
            b"eyJoZWxsbyI6IndvcmxkIn0.TORyNQab_MoXM7DvNKaTwbrJr4UY"
            b"d2SsX8hhlnWelQFmPFSf_JzC2EbLnar92t-bXsDovzxp25ExazrVHkfPkQ"
        )

        decoded_payload = jwt.decode(example_jwt, example_pubkey, algorithms=["ES256"])
        assert decoded_payload == example_payload

    # 'Control' RSA JWT created by another library.
    # Used to test for regressions that could affect both
    # encoding / decoding operations equally (causing tests
    # to still pass).
    @crypto_required
    def test_decodes_valid_rs384_jwt(self, jwt):
        example_payload = {"hello": "world"}
        with open(key_path("testkey_rsa.pub")) as fp:
            example_pubkey = fp.read()
        example_jwt = (
            b"eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9"
            b".eyJoZWxsbyI6IndvcmxkIn0"
            b".yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1X"
            b"lRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUju"
            b"O06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457"
            b"W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDx"
            b"mX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJ"
            b"urHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9t"
            b"uwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBr"
            b"qWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A"
        )
        decoded_payload = jwt.decode(example_jwt, example_pubkey, algorithms=["RS384"])

        assert decoded_payload == example_payload

    def test_decode_with_expiration(self, jwt, payload):
        payload["exp"] = utc_timestamp() - 1
        secret = "secret"
        jwt_message = jwt.encode(payload, secret)

        with pytest.raises(ExpiredSignatureError):
            jwt.decode(jwt_message, secret, algorithms=["HS256"])

    def test_decode_with_notbefore(self, jwt, payload):
        payload["nbf"] = utc_timestamp() + 10
        secret = "secret"
        jwt_message = jwt.encode(payload, secret)

        with pytest.raises(ImmatureSignatureError):
            jwt.decode(jwt_message, secret, algorithms=["HS256"])

    def test_decode_skip_expiration_verification(self, jwt, payload):
        payload["exp"] = time.time() - 1
    def test_decode_strict_aud_forbids_list_audience(self, jwt, payload):
        secret = "secret"
        payload["aud"] = "urn:foo"
        jwt_message = jwt.encode(payload, secret)

        # Decodes without `strict_aud`.
        jwt.decode(
            jwt_message,
            secret,
            audience=["urn:foo", "urn:bar"],
            options={"strict_aud": False},
            algorithms=["HS256"],
        )

        # Fails with `strict_aud`.
        with pytest.raises(InvalidAudienceError, match=r"Invalid audience \(strict\)"):
            jwt.decode(
                jwt_message,
                secret,
                audience=["urn:foo", "urn:bar"],
                options={"strict_aud": True},
                algorithms=["HS256"],
            )

    def test_decode_strict_aud_forbids_list_claim(self, jwt, payload):
        secret = "secret"
        payload["aud"] = ["urn:foo", "urn:bar"]
        jwt_message = jwt.encode(payload, secret)

        # Decodes without `strict_aud`.
        jwt.decode(
            jwt_message,
            secret,
            audience="urn:foo",
            options={"strict_aud": False},
            algorithms=["HS256"],
        )

        # Fails with `strict_aud`.
        with pytest.raises(
            InvalidAudienceError, match=r"Invalid claim format in token \(strict\)"
        ):
            jwt.decode(
                jwt_message,
                secret,
                audience="urn:foo",
                options={"strict_aud": True},
                algorithms=["HS256"],
            )

    def test_decode_strict_aud_does_not_match(self, jwt, payload):
        secret = "secret"
        payload["aud"] = "urn:foo"
        jwt_message = jwt.encode(payload, secret)

        with pytest.raises(
            InvalidAudienceError, match=r"Audience doesn't match \(strict\)"
        ):
            jwt.decode(
                jwt_message,
                secret,
                audience="urn:bar",
                options={"strict_aud": True},
                algorithms=["HS256"],
            )

    def test_decode_strict_ok(self, jwt, payload):
        secret = "secret"
        payload["aud"] = "urn:foo"
        jwt_message = jwt.encode(payload, secret)

        jwt.decode(
            jwt_message,
            secret,
            audience="urn:foo",
            options={"strict_aud": True},
            algorithms=["HS256"],
        )
[The command completed with exit code 0.]
[Current working directory: /workspace/pyjwt]
[Python interpreter: /usr/bin/python]
[Command finished with exit code 0]