예제 #1
0
파일: schema1.py 프로젝트: syed/quay
    def _validate(self):
        """
        Reference: https://docs.docker.com/registry/spec/manifest-v2-1/#signed-manifests
        """
        if not self._signatures:
            return

        payload_str = self._payload
        for signature in self._signatures:
            protected = signature[DOCKER_SCHEMA1_PROTECTED_KEY]
            sig = signature[DOCKER_SCHEMA1_SIGNATURE_KEY]

            jwk = JsonWebKey.import_key(
                signature[DOCKER_SCHEMA1_HEADER_KEY]["jwk"])
            jws = JsonWebSignature(
                algorithms=[signature[DOCKER_SCHEMA1_HEADER_KEY]["alg"]])

            obj_to_verify = {
                DOCKER_SCHEMA1_PROTECTED_KEY: protected,
                DOCKER_SCHEMA1_SIGNATURE_KEY: sig,
                DOCKER_SCHEMA1_HEADER_KEY: {
                    "alg": signature[DOCKER_SCHEMA1_HEADER_KEY]["alg"]
                },
                "payload": base64url_encode(payload_str),
            }

            try:
                data = jws.deserialize_json(obj_to_verify,
                                            jwk.get_public_key())
            except (BadSignatureError, UnsupportedAlgorithmError):
                raise InvalidSchema1Signature()

            if not data:
                raise InvalidSchema1Signature()
예제 #2
0
    def test_function_key(self):
        protected = {'alg': 'HS256'}
        header = [
            {
                'protected': protected,
                'header': {
                    'kid': 'a'
                }
            },
            {
                'protected': protected,
                'header': {
                    'kid': 'b'
                }
            },
        ]

        def load_key(header, payload):
            self.assertEqual(payload, b'hello')
            kid = header.get('kid')
            if kid == 'a':
                return 'secret-a'
            return 'secret-b'

        jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
        s = jws.serialize(header, b'hello', load_key)
        self.assertIsInstance(s, dict)
        self.assertIn('signatures', s)

        data = jws.deserialize(json.dumps(s), load_key)
        header, payload = data['header'], data['payload']
        self.assertEqual(payload, b'hello')
        self.assertEqual(header[0]['alg'], 'HS256')
        self.assertNotIn('signature', data)
예제 #3
0
 def test_compact_jws(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     s = jws.serialize({'alg': 'HS256'}, 'hello', 'secret')
     data = jws.deserialize(s, 'secret')
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'HS256')
     self.assertNotIn('signature', data)
예제 #4
0
 def get_jwt_token(self, user):
     now = int(time())
     rand = ''.join([choice(string.ascii_letters) for _ in range(10)])
     rands = f'{rand}.{now}'
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     headers = {'alg': 'HS256'}
     payload = json.dumps({'email': user.email})
     secret = bytes(self.app.config['SECRET_KEY'], 'utf-8')
     return jws.serialize_compact(headers, payload, secret)
예제 #5
0
파일: test_jws.py 프로젝트: imfht/flaskapps
 def test_ES256K_alg(self):
     jws = JsonWebSignature(algorithms=['ES256K'])
     private_key = read_file_path('secp256k1-private.pem')
     public_key = read_file_path('secp256k1-pub.pem')
     s = jws.serialize({'alg': 'ES256K'}, 'hello', private_key)
     data = jws.deserialize(s, public_key)
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'ES256K')
예제 #6
0
 def test_EdDSA_alg(self):
     jws = JsonWebSignature(algorithms=RFC8037_ALGORITHMS)
     private_key = read_file_path('ed25519-pkcs8.pem')
     public_key = read_file_path('ed25519-pub.pem')
     s = jws.serialize({'alg': 'EdDSA'}, 'hello', private_key)
     data = jws.deserialize(s, public_key)
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'EdDSA')
예제 #7
0
파일: test_jws.py 프로젝트: imfht/flaskapps
 def test_ES512_alg(self):
     jws = JsonWebSignature()
     private_key = read_file_path('secp521r1-private.json')
     public_key = read_file_path('secp521r1-public.json')
     self.assertRaises(ValueError, jws.serialize, {'alg': 'ES256'}, 'hello', private_key)
     s = jws.serialize({'alg': 'ES512'}, 'hello', private_key)
     data = jws.deserialize(s, public_key)
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'ES512')
예제 #8
0
 def test_validate_header(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     protected = {'alg': 'HS256', 'invalid': 'k'}
     header = {'protected': protected, 'header': {'kid': 'a'}}
     self.assertRaises(errors.InvalidHeaderParameterName, jws.serialize,
                       header, b'hello', 'secret')
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS,
                            private_headers=['invalid'])
     s = jws.serialize(header, b'hello', 'secret')
     self.assertIsInstance(s, dict)
예제 #9
0
 def test_compact_rsa_pss(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     private_key = read_file_path('rsa_private.pem')
     public_key = read_file_path('rsa_public.pem')
     s = jws.serialize({'alg': 'PS256'}, 'hello', private_key)
     data = jws.deserialize(s, public_key)
     header, payload = data['header'], data['payload']
     self.assertEqual(payload, b'hello')
     self.assertEqual(header['alg'], 'PS256')
     ssh_pub_key = read_file_path('ssh_public.pem')
     self.assertRaises(errors.BadSignatureError, jws.deserialize, s, ssh_pub_key)
예제 #10
0
    def test_flattened_json_jws(self):
        jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
        protected = {'alg': 'HS256'}
        header = {'protected': protected, 'header': {'kid': 'a'}}
        s = jws.serialize(header, 'hello', 'secret')
        self.assertIsInstance(s, dict)

        data = jws.deserialize(s, 'secret')
        header, payload = data['header'], data['payload']
        self.assertEqual(payload, b'hello')
        self.assertEqual(header['alg'], 'HS256')
        self.assertNotIn('protected', data)
예제 #11
0
    def test_compact_rsa(self):
        jws = JsonWebSignature()
        private_key = read_file_path('rsa_private.pem')
        public_key = read_file_path('rsa_public.pem')
        s = jws.serialize({'alg': 'RS256'}, 'hello', private_key)
        data = jws.deserialize(s, public_key)
        header, payload = data['header'], data['payload']
        self.assertEqual(payload, b'hello')
        self.assertEqual(header['alg'], 'RS256')

        # can deserialize with private key
        data2 = jws.deserialize(s, private_key)
        self.assertEqual(data, data2)

        ssh_pub_key = read_file_path('ssh_public.pem')
        self.assertRaises(errors.BadSignatureError, jws.deserialize, s, ssh_pub_key)
예제 #12
0
    def test_nested_json_jws(self):
        jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
        protected = {'alg': 'HS256'}
        header = {'protected': protected, 'header': {'kid': 'a'}}
        s = jws.serialize([header], 'hello', 'secret')
        self.assertIsInstance(s, dict)
        self.assertIn('signatures', s)

        data = jws.deserialize(s, 'secret')
        header, payload = data['header'], data['payload']
        self.assertEqual(payload, b'hello')
        self.assertEqual(header[0]['alg'], 'HS256')
        self.assertNotIn('signatures', data)

        # test bad signature
        self.assertRaises(errors.BadSignatureError, jws.deserialize, s, 'f')
예제 #13
0
 def test_invalid_alg(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     self.assertRaises(errors.UnsupportedAlgorithmError, jws.deserialize,
                       'eyJhbGciOiJzIn0.YQ.YQ', 'k')
     self.assertRaises(errors.MissingAlgorithmError, jws.serialize, {}, '',
                       'k')
     self.assertRaises(errors.UnsupportedAlgorithmError, jws.serialize,
                       {'alg': 's'}, '', 'k')
예제 #14
0
def verify_credential(signed_credential, did):
    """
    Verify credential signed with RSA key of the DID
    @parma signed_credential as a dict
    @param did as a str
    return bool
    """
    read = requests.get('https://talao.co/resolver?did=' + did)
    for Key in read.json()['publicKey']:
        if Key.get('id') == did + "#secondary":
            public_key = Key['publicKeyPem']
            break
    jws = JsonWebSignature()
    try:
        jws.deserialize_compact(signed_credential['proof']['jws'], public_key)
    except:
        return False
    return True
예제 #15
0
def json_verify(msg: Union[bytes, dict, str],
                pubKey: Union[str, Dict[str, str]] = None) -> bool:
    msg: dict = msg if isinstance(msg, dict) else json.loads(msg)
    if signature := msg.pop("signature", None):
        sig = signature.split(".")
        header = json.loads(base64.b64decode(sig[0]))
        sig[1] = base64.b64encode(b'.'.join([
            base64.b64encode(canonicaljson.encode_canonical_json(header)),
            base64.b64encode(canonicaljson.encode_canonical_json(msg))
        ])).decode("utf-8").rstrip("=")

        jws = JsonWebSignature()
        key = Path(pubKey).read_bytes() if isinstance(
            pubKey, str) else partial(load_key, keys=pubKey)
        try:
            jws.deserialize_compact(".".join(sig), key)
            return True
        except errors.BadSignatureError:
            return False
예제 #16
0
def json_sign(msg: Union[dict, str], privKey: str) -> dict:
    msg: dict = json.loads(msg) if isinstance(msg, str) else msg
    if not privKey:
        raise ValueError("privKey was not passed as a param")

    header = {
        "alg": "ES256",
        "kid": msg.get("headers", {}).get("from", "ORIGIN")
    }
    sig_payload = b".".join([
        base64.b64encode(canonicaljson.encode_canonical_json(header)),
        base64.b64encode(canonicaljson.encode_canonical_json(msg))
    ])
    jws = JsonWebSignature()
    key = Path(privKey).read_bytes()
    sig = jws.serialize_compact(header, sig_payload,
                                key).decode("utf-8").split('.')
    msg["signature"] = f"{sig[0]}..{sig[2]}"
    return msg
예제 #17
0
def sign_credential(credential, key):
    """
    Sign credential with RSA key of the did, add the signature as linked data JSONLD
    @parma credential as a dict
    #param key a string PEM private RSA key
    return signed credential as a dict
    """
    payload = json.dumps(credential)
    credential_jws = JsonWebSignature(algorithms=['RS256'])
    protected = {'alg': 'RS256'}
    signature = credential_jws.serialize_compact(protected, payload,
                                                 key.encode()).decode()
    credential["proof"] = {
        "type": "RsaSignature2018",
        "created": datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
        "proofPurpose": "assertionMethod",
        "verificationMethod": "https://talao.readthedocs.io/en/latest/",
        "jws": signature
    }
    return credential
예제 #18
0
    def test_register_invalid_algorithms(self):
        self.assertRaises(
            ValueError,
            JsonWebSignature,
            ['INVALID']
        )

        jws = JsonWebSignature(algorithms=[])
        self.assertRaises(
            ValueError,
            jws.register_algorithm,
            JWE_ALGORITHMS[0]
        )
예제 #19
0
    def test_fail_deserialize_json(self):
        jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
        self.assertRaises(errors.DecodeError, jws.deserialize_json, None, '')
        self.assertRaises(errors.DecodeError, jws.deserialize_json, '[]', '')
        self.assertRaises(errors.DecodeError, jws.deserialize_json, '{}', '')

        # missing protected
        s = json.dumps({'payload': 'YQ'})
        self.assertRaises(errors.DecodeError, jws.deserialize_json, s, '')

        # missing signature
        s = json.dumps({'payload': 'YQ', 'protected': 'YQ'})
        self.assertRaises(errors.DecodeError, jws.deserialize_json, s, '')
예제 #20
0
 def test_invalid_input(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     self.assertRaises(errors.DecodeError, jws.deserialize, 'a', 'k')
     self.assertRaises(errors.DecodeError, jws.deserialize, 'a.b.c', 'k')
     self.assertRaises(errors.DecodeError, jws.deserialize, 'YQ.YQ.YQ',
                       'k')  # a
     self.assertRaises(errors.DecodeError, jws.deserialize, 'W10.a.YQ',
                       'k')  # []
     self.assertRaises(errors.DecodeError, jws.deserialize, 'e30.a.YQ',
                       'k')  # {}
     self.assertRaises(errors.DecodeError, jws.deserialize,
                       'eyJhbGciOiJzIn0.a.YQ', 'k')
     self.assertRaises(errors.DecodeError, jws.deserialize,
                       'eyJhbGciOiJzIn0.YQ.a', 'k')
    def get_token(self):
        """Return a JWT token and expiration time for making API calls to Small World Community

        Arguments to this function will, by default, use environmental variables if they are present (noted below)

        :param community_domain: the FQDN of the community instance (SWC_AUDIENCE)
        :param app_id: the the Oauth Application ID being used to connect to the community API (SWC_APP_ID)
        :param user_id: The SWC User ID of the authorized user attached to this Oauth Application (SWC_USER_ID)
        :return: A tuple with token to use with request calls and the time (in seconds) when the token will expire
        """
        exp = int(time.time()) + TOKEN_DURATION
        payload = {
            "iss": self.app_id,
            "iat": int(time.time()),
            "aud": self.community_domain,
            "exp": exp,
            "sub": self.user_id,
            "scope": SWC_SCOPE,
        }
        jws = JsonWebSignature(["HS256"])
        auth_token = jws.serialize_compact(
            JWT_TOKEN_HEADER,
            bytearray(json.dumps(payload), "utf-8"),
            bytearray(self.app_secret, "utf-8"),
        )
        swc_token_url = f"https://{self.community_domain}/services/4.0/token"
        token_request = requests.post(
            swc_token_url,
            data={
                "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
                "assertion": auth_token.decode("utf-8"),
                "content_type": "application/x-www-form-urlencoded",
            },
        )
        token_request.raise_for_status()
        token = token_request.json().get("access_token")
        return token, exp
예제 #22
0
    def test_not_supported_alg(self):
        jws = JsonWebSignature(algorithms=['HS256'])
        s = jws.serialize({'alg': 'HS256'}, 'hello', 'secret')

        jws = JsonWebSignature(algorithms=['RS256'])
        self.assertRaises(
            errors.UnsupportedAlgorithmError,
            lambda: jws.serialize({'alg': 'HS256'}, 'hello', 'secret'))

        self.assertRaises(errors.UnsupportedAlgorithmError, jws.deserialize, s,
                          'secret')
예제 #23
0
파일: schema1.py 프로젝트: syed/quay
    def build(self, json_web_key=None, ensure_ascii=True):
        """
        Builds a DockerSchema1Manifest object, with optional signature.

        NOTE: For backward compatibility, "JWS JSON Serialization" is used instead of "JWS Compact Serialization", since the latter **requires** that the
        "alg" headers be carried in the **protected** headers, which was never done before migrating to authlib (One shouldn't be using schema1 anyways)

        References:
            - https://tools.ietf.org/html/rfc7515#section-10.7
            - https://docs.docker.com/registry/spec/manifest-v2-1/#signed-manifests
        """
        payload = OrderedDict(self._base_payload)
        payload.update({
            DOCKER_SCHEMA1_HISTORY_KEY: self._history,
            DOCKER_SCHEMA1_FS_LAYERS_KEY: self._fs_layer_digests,
        })

        payload_str = json.dumps(payload, indent=3, ensure_ascii=ensure_ascii)
        if json_web_key is None:
            return DockerSchema1Manifest(
                Bytes.for_string_or_unicode(payload_str))

        payload_str = Bytes.for_string_or_unicode(payload_str).as_encoded_str()
        split_point = payload_str.rfind(b"\n}")

        protected_payload = {
            DOCKER_SCHEMA1_FORMAT_TAIL_KEY:
            base64url_encode(payload_str[split_point:]).decode("ascii"),
            DOCKER_SCHEMA1_FORMAT_LENGTH_KEY:
            split_point,
            "time":
            datetime.utcnow().strftime(_ISO_DATETIME_FORMAT_ZULU),
        }

        # Flattened JSON serialization header
        jws = JsonWebSignature(algorithms=[_JWS_SIGNING_ALGORITHM])
        headers = {
            "protected": protected_payload,
            "header": {
                "alg": _JWS_SIGNING_ALGORITHM
            },
        }

        signed = jws.serialize_json(headers, payload_str,
                                    json_web_key.get_private_key())
        protected = signed["protected"]
        signature = signed["signature"]
        logger.debug("Generated signature: %s", signature)
        logger.debug("Generated protected block: %s", protected)

        public_members = set(json_web_key.REQUIRED_JSON_FIELDS +
                             json_web_key.ALLOWED_PARAMS)
        public_key = {
            comp: value
            for comp, value in list(json_web_key.as_dict().items())
            if comp in public_members
        }
        public_key["kty"] = json_web_key.kty

        signature_block = {
            DOCKER_SCHEMA1_HEADER_KEY: {
                "jwk": public_key,
                "alg": _JWS_SIGNING_ALGORITHM
            },
            DOCKER_SCHEMA1_SIGNATURE_KEY: signature,
            DOCKER_SCHEMA1_PROTECTED_KEY: protected,
        }

        logger.debug("Encoded signature block: %s",
                     json.dumps(signature_block))
        payload.update({DOCKER_SCHEMA1_SIGNATURES_KEY: [signature_block]})

        json_str = json.dumps(payload, indent=3, ensure_ascii=ensure_ascii)
        return DockerSchema1Manifest(Bytes.for_string_or_unicode(json_str))
예제 #24
0
    def build(self, json_web_key=None, ensure_ascii=True):
        """
        Builds a DockerSchema1Manifest object, with optional signature.

        NOTE: For backward compatibility, "JWS JSON Serialization" is used instead of "JWS Compact Serialization", since the latter **requires** that the
        "alg" headers be carried in the **protected** headers, which was never done before migrating to authlib (One shouldn't be using schema1 anyways)

        References:
            - https://tools.ietf.org/html/rfc7515#section-10.7
            - https://docs.docker.com/registry/spec/manifest-v2-1/#signed-manifests
        """
        payload = OrderedDict(self._base_payload)
        payload.update({
            DOCKER_SCHEMA1_HISTORY_KEY: self._history,
            DOCKER_SCHEMA1_FS_LAYERS_KEY: self._fs_layer_digests,
        })

        payload_str = json.dumps(payload, indent=3, ensure_ascii=ensure_ascii)
        if json_web_key is None:
            return DockerSchema1Manifest(
                Bytes.for_string_or_unicode(payload_str))

        payload_str = Bytes.for_string_or_unicode(payload_str).as_encoded_str()
        split_point = payload_str.rfind(b"\n}")

        protected_payload = {
            DOCKER_SCHEMA1_FORMAT_TAIL_KEY:
            base64url_encode(payload_str[split_point:]).decode("ascii"),
            DOCKER_SCHEMA1_FORMAT_LENGTH_KEY:
            split_point,
            "time":
            datetime.utcnow().strftime(_ISO_DATETIME_FORMAT_ZULU),
        }

        # Flattened JSON serialization header
        jws = JsonWebSignature(algorithms=[_JWS_SIGNING_ALGORITHM])
        headers = {
            "protected": protected_payload,
            "header": {
                "alg": _JWS_SIGNING_ALGORITHM
            },
        }

        signed = jws.serialize_json(headers, payload_str,
                                    json_web_key.get_private_key())
        protected = signed["protected"]
        signature = signed["signature"]
        logger.debug("Generated signature: %s", signature)
        logger.debug("Generated protected block: %s", protected)

        public_members = set(json_web_key.REQUIRED_JSON_FIELDS +
                             json_web_key.ALLOWED_PARAMS)
        public_key = {
            comp: value
            for comp, value in list(json_web_key.as_dict().items())
            if comp in public_members
        }
        public_key["kty"] = json_web_key.kty

        # Signed Docker schema 1 manifests require the kid to be in a specific format
        # https://docs.docker.com/registry/spec/auth/jwt/
        pub_key = json_web_key.get_public_key()
        # Take the DER encoded public key which the JWT token was signed against
        key_der = pub_key.public_bytes(
            encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo)
        # Create a SHA256 hash out of it and truncate to 240bits
        hash256 = sha256()
        hash256.update(key_der)
        digest = hash256.digest()
        digest_first_240_bits = digest[:30]
        # Split the result into 12 base32 encoded groups with : as delimiter
        base32 = base64.b32encode(digest_first_240_bits).decode("ascii")
        kid = ""
        i = 0
        for i in range(0, int(len(base32) / 4) - 1):
            start = i * 4
            end = start + 4
            kid += base32[start:end] + ":"
        kid += base32[(i + 1) * 4:]  # Add the last group without the delimiter
        public_key["kid"] = kid

        signature_block = {
            DOCKER_SCHEMA1_HEADER_KEY: {
                "jwk": public_key,
                "alg": _JWS_SIGNING_ALGORITHM
            },
            DOCKER_SCHEMA1_SIGNATURE_KEY: signature,
            DOCKER_SCHEMA1_PROTECTED_KEY: protected,
        }

        logger.debug("Encoded signature block: %s",
                     json.dumps(signature_block))
        payload.update({DOCKER_SCHEMA1_SIGNATURES_KEY: [signature_block]})

        json_str = json.dumps(payload, indent=3, ensure_ascii=ensure_ascii)
        return DockerSchema1Manifest(Bytes.for_string_or_unicode(json_str))
예제 #25
0
 def validate_jwt_token(self, token):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     secret = bytes(self.app.config['SECRET_KEY'], 'utf-8')
     data = jws.deserialize_compact(token, secret)
     return json.loads(data['payload'])
예제 #26
0
 def test_compact_none(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     s = jws.serialize({'alg': 'none'}, 'hello', '')
     self.assertRaises(errors.BadSignatureError, jws.deserialize, s, '')
예제 #27
0
 def test_bad_signature(self):
     jws = JsonWebSignature(algorithms=JWS_ALGORITHMS)
     s = 'eyJhbGciOiJIUzI1NiJ9.YQ.YQ'
     self.assertRaises(errors.BadSignatureError, jws.deserialize, s, 'k')
예제 #28
0
def test_keys():
    """Try to store/get/remove keys"""
    # JWS
    jws = JsonWebSignature(algorithms=["RS256"])
    code_payload = {
        "user_id": "user",
        "scope": "scope",
        "client_id": "client",
        "redirect_uri": "redirect_uri",
        "code_challenge": "code_challenge",
    }

    # Token metadata
    header = {"alg": "RS256"}
    payload = {
        "sub": "user",
        "iss": "issuer",
        "scope": "scope",
        "setup": "setup",
        "group": "my_group"
    }

    # Remove all keys
    result = db.removeKeys()
    assert result["OK"], result["Message"]

    # Check active keys
    result = db.getActiveKeys()
    assert result["OK"], result["Message"]
    assert result["Value"] == []

    # Create new one
    result = db.getPrivateKey()
    assert result["OK"], result["Message"]

    private_key = result["Value"]
    assert isinstance(private_key, RSAKey)

    # Sign token
    header["kid"] = private_key.thumbprint()

    # Find key by KID
    result = db.getPrivateKey(header["kid"])
    assert result["OK"], result["Message"]
    # as_dict has no arguments for authlib < 1.0.0
    # for authlib >= 1.0.0:
    assert result["Value"].as_dict(True) == private_key.as_dict(True)

    # Sign token
    token = jwt.encode(header, payload, private_key)
    # Sign auth code
    code = jws.serialize_compact(header, json_b64encode(code_payload),
                                 private_key)

    # Get public key set
    result = db.getKeySet()
    keyset = result["Value"]
    assert result["OK"], result["Message"]
    # as_dict has no arguments for authlib < 1.0.0
    # for authlib >= 1.0.0:
    assert bool([
        key for key in keyset.as_dict(True)["keys"]
        if key["kid"] == header["kid"]
    ])

    # Read token
    _payload = jwt.decode(token, JsonWebKey.import_key_set(keyset.as_dict()))
    assert _payload == payload
    # Read auth code
    data = jws.deserialize_compact(code, keyset.keys[0])
    _code_payload = json_loads(urlsafe_b64decode(data["payload"]))
    assert _code_payload == code_payload