def test_validate_issued_at(self): in_one_minute = (datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=1)) one_minute_ago = (datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(minutes=1)) token_with_issued_at_in_the_future = jwt.new_raw_jwt( issued_at=in_one_minute, without_expiration=True) token_with_issued_at_in_the_past = jwt.new_raw_jwt( issued_at=one_minute_ago, without_expiration=True) token_without_issued_at = jwt.new_raw_jwt(without_expiration=True) validator = jwt.new_validator(allow_missing_expiration=True) _jwt_validator.validate(validator, token_with_issued_at_in_the_future) _jwt_validator.validate(validator, token_with_issued_at_in_the_past) _jwt_validator.validate(validator, token_without_issued_at) issued_at_validator = jwt.new_validator( expect_issued_in_the_past=True, allow_missing_expiration=True) with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(issued_at_validator, token_with_issued_at_in_the_future) _jwt_validator.validate(issued_at_validator, token_with_issued_at_in_the_past) with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(issued_at_validator, token_without_issued_at)
def test_ignore_subject_success(self): validator = jwt.new_validator( ignore_subject=True, allow_missing_expiration=True) token_without_subject = jwt.new_raw_jwt(without_expiration=True) _jwt_validator.validate(validator, token_without_subject) token_with_subject = jwt.new_raw_jwt( subject='subject', without_expiration=True) _jwt_validator.validate(validator, token_with_subject)
def test_ignore_audiences_success(self): validator = jwt.new_validator( ignore_audiences=True, allow_missing_expiration=True) token_without_audience = jwt.new_raw_jwt(without_expiration=True) _jwt_validator.validate(validator, token_without_audience) token_with_audience = jwt.new_raw_jwt( audiences=['audience'], without_expiration=True) _jwt_validator.validate(validator, token_with_audience)
def test_ignore_issuer_success(self): validator = jwt.new_validator( ignore_issuer=True, allow_missing_expiration=True) token_without_issuer = jwt.new_raw_jwt(without_expiration=True) _jwt_validator.validate(validator, token_without_issuer) token_with_issuer = jwt.new_raw_jwt( issuer='issuer', without_expiration=True) _jwt_validator.validate(validator, token_with_issuer)
def test_empty(self): token = jwt.VerifiedJwt._create(jwt.new_raw_jwt()) with self.assertRaises(KeyError): token.type_header() with self.assertRaises(KeyError): token.issuer() with self.assertRaises(KeyError): token.subject() with self.assertRaises(KeyError): token.jwt_id() with self.assertRaises(KeyError): token.audiences() with self.assertRaises(KeyError): token.expiration() with self.assertRaises(KeyError): token.issued_at() with self.assertRaises(KeyError): token.not_before() with self.assertRaises(KeyError): token.custom_claim('unknown') self.assertFalse(token.has_issuer()) self.assertFalse(token.has_subject()) self.assertFalse(token.has_jwt_id()) self.assertFalse(token.has_audiences()) self.assertFalse(token.has_expiration()) self.assertFalse(token.has_issued_at()) self.assertFalse(token.has_not_before())
def test_new_keydata_primitive_success(self, template): key_manager = _jwt_hmac_key_manager.MacCcToPyJwtMacKeyManager() key_data = key_manager.new_key_data(template) jwt_hmac = key_manager.primitive(key_data) raw_jwt = jwt.new_raw_jwt( type_header='typeHeader', issuer='issuer', without_expiration=True) validator = jwt.new_validator( expected_type_header='typeHeader', expected_issuer='issuer', allow_missing_expiration=True, fixed_now=DATETIME_1970) token_with_kid = jwt_hmac.compute_mac_and_encode_with_kid( raw_jwt, kid='kid-123') token_without_kid = jwt_hmac.compute_mac_and_encode_with_kid( raw_jwt, kid=None) # Verification of a token with a kid only fails if the wrong kid is passed. verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid( token_with_kid, validator, kid='kid-123') self.assertEqual(verified_jwt.type_header(), 'typeHeader') self.assertEqual(verified_jwt.issuer(), 'issuer') jwt_hmac.verify_mac_and_decode_with_kid(token_with_kid, validator, kid=None) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_with_kid, validator, kid='other-kid') # A token without kid is only valid if no kid is passed. jwt_hmac.verify_mac_and_decode_with_kid( token_without_kid, validator, kid=None) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_without_kid, validator, kid='kid-123')
def test_validate_not_before_almost_reached_with_clock_skew_success(self): in_one_minute = (datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=1)) token = jwt.new_raw_jwt(not_before=in_one_minute, without_expiration=True) validator = jwt.new_validator( allow_missing_expiration=True, clock_skew=datetime.timedelta(minutes=2)) _jwt_validator.validate(validator, token)
def test_jwt_signature_without_primary(self, key_template_name, lang): """Unsets the primary key and tries to sign and verify JWT signatures.""" template = supported_key_types.KEY_TEMPLATE[key_template_name] private_keyset = testing_servers.new_keyset(lang, template) public_keyset = testing_servers.public_keyset(lang, private_keyset) signer = testing_servers.jwt_public_key_sign(lang, private_keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) raw_jwt = jwt.new_raw_jwt(issuer='issuer', expiration=now + datetime.timedelta(seconds=100)) token = signer.sign_and_encode(raw_jwt) signer_without_primary = testing_servers.jwt_public_key_sign( lang, unset_primary(private_keyset)) with self.assertRaises(tink.TinkError): signer_without_primary.sign_and_encode(raw_jwt) verifier_without_primary = testing_servers.jwt_public_key_verify( lang, unset_primary(public_keyset)) validator = jwt.new_validator(expected_issuer='issuer', fixed_now=now) if lang in ['cc', 'java', 'python']: # C++, Java and Python currently allow this. verifier_without_primary.verify_and_decode(token, validator) else: with self.assertRaises(tink.TinkError): verifier_without_primary.verify_and_decode(token, validator)
def test_ps256_key_with_a_custom_kid_header(self): keyset_handle = tink.new_keyset_handle( jwt.raw_jwt_ps256_2048_f4_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value pss_key = jwt_rsa_ssa_pss_pb2.JwtRsaSsaPssPrivateKey.FromString(value) pss_key.public_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = pss_key.SerializeToString() sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) tink_sign.sign_and_encode(raw_jwt)
def test_only_tink_output_prefix_type_encodes_a_kid_header(self): handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) jwt_mac = handle.primitive(jwt.JwtMac) tink_handle = _change_output_prefix_to_tink(handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = jwt_mac.compute_mac_and_encode(raw_jwt) token_with_kid = tink_jwt_mac.compute_mac_and_encode(raw_jwt) _, header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(header)) _, header_with_kid, _, _ = _jwt_format.split_signed_compact( token_with_kid) self.assertIn('kid', _json_util.json_loads(header_with_kid)) validator = jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True) jwt_mac.verify_mac_and_decode(token, validator) tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type RAW, a kid header is ignored jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type TINK, a kid header is required. with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) other_handle = _change_key_id(tink_handle) other_jwt_mac = other_handle.primitive(jwt.JwtMac) # A token with a wrong kid is rejected, even if the signature is ok. with self.assertRaises(tink.TinkError): other_jwt_mac.verify_mac_and_decode(token_with_kid, validator)
def test_jwt_public_key_sign_verify(self, lang): key_format = jwt_ecdsa_pb2.JwtEcdsaKeyFormat( algorithm=jwt_ecdsa_pb2.ES256) key_template = tink_pb2.KeyTemplate( type_url='type.googleapis.com/google.crypto.tink.JwtEcdsaPrivateKey', value=key_format.SerializeToString(), output_prefix_type=tink_pb2.RAW) private_keyset = testing_servers.new_keyset(lang, key_template) public_keyset = testing_servers.public_keyset(lang, private_keyset) signer = testing_servers.jwt_public_key_sign(lang, private_keyset) verifier = testing_servers.jwt_public_key_verify(lang, public_keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt( issuer='issuer', subject='subject', audiences=['audience1', 'audience2'], jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=10), custom_claims={'switch': True, 'pi': 3.14159}) compact = signer.sign_and_encode(token) validator = jwt.new_validator(audience='audience1', fixed_now=now) verified_jwt = verifier.verify_and_decode(compact, validator) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject') self.assertEqual(verified_jwt.jwt_id(), 'jwt_id') self.assertEqual(verified_jwt.custom_claim('switch'), True) self.assertEqual(verified_jwt.custom_claim('pi'), 3.14159) validator2 = jwt.new_validator(audience='wrong_audience', fixed_now=now) with self.assertRaises(tink.TinkError): verifier.verify_and_decode(compact, validator2)
def test_jwt_mac(self, lang): key_format = jwt_hmac_pb2.JwtHmacKeyFormat( hash_type=common_pb2.SHA256, key_size=32) key_template = tink_pb2.KeyTemplate( type_url='type.googleapis.com/google.crypto.tink.JwtHmacKey', value=key_format.SerializeToString(), output_prefix_type=tink_pb2.RAW) keyset = testing_servers.new_keyset(lang, key_template) jwt_mac_primitive = testing_servers.jwt_mac(lang, keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt( issuer='issuer', subject='subject', audiences=['audience1', 'audience2'], jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=10), custom_claims={'switch': True, 'pi': 3.14159}) compact = jwt_mac_primitive.compute_mac_and_encode(token) validator = jwt.new_validator(audience='audience1', fixed_now=now) verified_jwt = jwt_mac_primitive.verify_mac_and_decode(compact, validator) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject') self.assertEqual(verified_jwt.jwt_id(), 'jwt_id') self.assertEqual(verified_jwt.custom_claim('switch'), True) self.assertEqual(verified_jwt.custom_claim('pi'), 3.14159) validator2 = jwt.new_validator(audience='wrong_audience', fixed_now=now) with self.assertRaises(tink.TinkError): jwt_mac_primitive.verify_mac_and_decode(compact, validator2)
def test_custom_claims(self): custom_claims = { 'string': 'value', 'boolean': True, 'number': 123.456, 'integer': 123, 'null': None, 'array': [1, None, 'Bob', 2.2, { 'foo': 'bar' }], 'object': { 'one': { 'two': 3 } } } token = jwt.new_raw_jwt(custom_claims=custom_claims) self.assertCountEqual(token.custom_claim_names(), { 'string', 'boolean', 'number', 'integer', 'null', 'array', 'object' }) self.assertEqual(token.custom_claim('string'), 'value') self.assertEqual(token.custom_claim('boolean'), True) self.assertEqual(token.custom_claim('number'), 123.456) self.assertEqual(token.custom_claim('integer'), 123) self.assertIsNone(token.custom_claim('null')) self.assertEqual(token.custom_claim('array'), [1, None, 'Bob', 2.2, { 'foo': 'bar' }]) self.assertEqual(token.custom_claim('object'), {'one': {'two': 3}})
def test_full(self): token = jwt.VerifiedJwt._create( jwt.new_raw_jwt(type_header='TypeHeader', issuer='Issuer', subject='Subject', jwt_id='JWT ID', audiences=['bob', 'eve'], expiration=EXPIRATION, issued_at=ISSUED_AT, not_before=NOT_BEFORE)) self.assertTrue(token.has_type_header()) self.assertEqual(token.type_header(), 'TypeHeader') self.assertTrue(token.has_issuer()) self.assertEqual(token.issuer(), 'Issuer') self.assertTrue(token.has_subject()) self.assertEqual(token.subject(), 'Subject') self.assertTrue(token.has_jwt_id()) self.assertEqual(token.jwt_id(), 'JWT ID') self.assertTrue(token.has_audiences()) self.assertEqual(token.audiences(), ['bob', 'eve']) self.assertTrue(token.has_expiration()) self.assertEqual(token.expiration(), EXPIRATION) self.assertTrue(token.has_issued_at()) self.assertEqual(token.issued_at(), ISSUED_AT) self.assertTrue(token.has_not_before()) self.assertEqual(token.not_before(), NOT_BEFORE)
def test_jwt_public_key_sign_verify(self, lang): private_keyset = testing_servers.new_keyset(lang, jwt.jwt_es256_template()) public_keyset = testing_servers.public_keyset(lang, private_keyset) signer = testing_servers.jwt_public_key_sign(lang, private_keyset) verifier = testing_servers.jwt_public_key_verify(lang, public_keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt( issuer='issuer', subject='subject', audiences=['audience1', 'audience2'], jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=10), custom_claims={'switch': True, 'pi': 3.14159}) compact = signer.sign_and_encode(token) validator = jwt.new_validator( expected_issuer='issuer', expected_audience='audience1', fixed_now=now) verified_jwt = verifier.verify_and_decode(compact, validator) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject') self.assertEqual(verified_jwt.jwt_id(), 'jwt_id') self.assertEqual(verified_jwt.custom_claim('switch'), True) self.assertEqual(verified_jwt.custom_claim('pi'), 3.14159) validator2 = jwt.new_validator( expected_audience='wrong_audience', fixed_now=now) with self.assertRaises(tink.TinkError): verifier.verify_and_decode(compact, validator2)
def test_validate_not_before_in_the_future_fails(self): in_the_future = (datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=1)) token = jwt.new_raw_jwt(not_before=in_the_future) validator = jwt.new_validator() with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(validator, token)
def test_payload(self): custom_claims = {'account_no': 1234, 'amount': 1.5, 'name': 'Peter', 'null': None, 'array': [1, None, 'Bob', 2.2, {'foo': 'bar'}], 'object': {'one': {'two': 3}} } token = jwt.new_raw_jwt( issuer='Issuer', subject='Subject', audiences=['bob', 'eve'], jwt_id='JWT ID', issued_at=ISSUED_AT, not_before=NOT_BEFORE, expiration=EXPIRATION, custom_claims=custom_claims) self.assertEqual( json.loads(token.json_payload()), { 'iss': 'Issuer', 'sub': 'Subject', 'jti': 'JWT ID', 'aud': ['bob', 'eve'], 'iat': ISSUED_AT_TIMESTAMP, 'nbf': NOT_BEFORE_TIMESTAMP, 'exp': EXPIRATION_TIMESTAMP, 'account_no': 1234, 'amount': 1.5, 'name': 'Peter', 'null': None, 'array': [1, None, 'Bob', 2.2, {'foo': 'bar'}], 'object': {'one': {'two': 3}} })
def test_validate_expired_fails(self): expired = (datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(minutes=1)) token = jwt.new_raw_jwt(expiration=expired) validator = jwt.new_validator() with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(validator, token)
def test_validate_recently_expired_with_clock_skew_success(self): recently_expired = (datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(minutes=1)) token = jwt.new_raw_jwt(expiration=recently_expired) validator = jwt.new_validator(clock_skew=datetime.timedelta(minutes=2)) # because of clock_skew, the recently expired token is valid _jwt_validator.validate(validator, token)
def test_validate_with_fixed_now_valid_success(self): fixed_now = datetime.datetime.fromtimestamp(12345, datetime.timezone.utc) validator = jwt.new_validator(fixed_now=fixed_now) expiration = fixed_now + datetime.timedelta(minutes=1) not_before = fixed_now - datetime.timedelta(minutes=1) token = jwt.new_raw_jwt(expiration=expiration, not_before=not_before) _jwt_validator.validate(validator, token)
def test_jwt_mac(self, lang): keyset = testing_servers.new_keyset(lang, jwt.jwt_hs256_template()) jwt_mac_primitive = testing_servers.jwt_mac(lang, keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt(issuer='issuer', subject='subject', audiences=['audience1', 'audience2'], jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=10), custom_claims={ 'switch': True, 'pi': 3.14159 }) compact = jwt_mac_primitive.compute_mac_and_encode(token) validator = jwt.new_validator(audience='audience1', fixed_now=now) # HERE verified_jwt = jwt_mac_primitive.verify_mac_and_decode( compact, validator) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject') self.assertEqual(verified_jwt.jwt_id(), 'jwt_id') self.assertEqual(verified_jwt.custom_claim('switch'), True) self.assertEqual(verified_jwt.custom_claim('pi'), 3.14159) validator2 = jwt.new_validator(audience='wrong_audience', fixed_now=now) with self.assertRaises(tink.TinkError): jwt_mac_primitive.verify_mac_and_decode(compact, validator2)
def test_round_down_not_before_with_fraction(self): token = jwt.new_raw_jwt(without_expiration=True, not_before=datetime.datetime.fromtimestamp( 123.999, datetime.timezone.utc)) self.assertEqual( token.not_before(), datetime.datetime.fromtimestamp(123, datetime.timezone.utc))
def test_round_down_issued_at_with_fraction(self): token = jwt.new_raw_jwt(without_expiration=True, issued_at=datetime.datetime.fromtimestamp( 123.999, datetime.timezone.utc)) self.assertEqual( token.issued_at(), datetime.datetime.fromtimestamp(123, datetime.timezone.utc))
def main(argv): del argv # Unused. # Initialise Tink try: jwt.register_jwt_signature() except tink.TinkError as e: logging.exception('Error initialising Tink: %s', e) return 1 # Read the keyset into a keyset_handle with open(FLAGS.keyset_path, 'rt') as keyset_file: try: text = keyset_file.read() keyset_handle = cleartext_keyset_handle.read( tink.JsonKeysetReader(text)) except tink.TinkError as e: logging.exception('Error reading keyset: %s', e) return 1 now = datetime.datetime.now(tz=datetime.timezone.utc) if FLAGS.mode == 'sign': # Get the JwtPublicKeySign primitive try: jwt_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) except tink.TinkError as e: logging.exception('Error creating JwtPublicKeySign: %s', e) return 1 # Create token raw_jwt = jwt.new_raw_jwt(subject=FLAGS.subject, expiration=now + datetime.timedelta(seconds=100)) token = jwt_sign.sign_and_encode(raw_jwt) with open(FLAGS.token_path, 'wt') as token_file: token_file.write(token) logging.info('Token has been written to %s', FLAGS.token_path) return 0 # Get the JwtPublicKeyVerify primitive try: jwt_verify = keyset_handle.primitive(jwt.JwtPublicKeyVerify) except tink.TinkError as e: logging.exception('Error creating JwtPublicKeyVerify: %s', e) return 1 # Verify token with open(FLAGS.token_path, 'rt') as token_file: token = token_file.read() validator = jwt.new_validator(expected_subject=FLAGS.subject) try: verified_jwt = jwt_verify.verify_and_decode(token, validator) expires_in = verified_jwt.expiration() - now logging.info('Token is valid and expires in %s seconds', expires_in.seconds) return 0 except tink.TinkError as e: logging.info('JWT verification failed: %s', e) return 1
def test_validate_with_fixed_now_not_yet_valid_fails(self): two_minutes_ago = (datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(minutes=2)) one_minute_ago = two_minutes_ago + datetime.timedelta(minutes=1) token = jwt.new_raw_jwt(not_before=one_minute_ago) validator = jwt.new_validator(fixed_now=two_minutes_ago) with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(validator, token)
def test_validate_with_fixed_now_expired_fails(self): in_two_minutes = (datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=2)) in_one_minute = in_two_minutes - datetime.timedelta(minutes=1) token = jwt.new_raw_jwt(expiration=in_one_minute) validator = jwt.new_validator(fixed_now=in_two_minutes) with self.assertRaises(jwt.JwtInvalidError): _jwt_validator.validate(validator, token)
def test_jwt_mac_sets_custom_kid_for_raw_keys(self, template_name): keyset = generate_jwt_mac_keyset_with_custom_kid( template_name=template_name, custom_kid='my kid') raw_jwt = jwt.new_raw_jwt(without_expiration=True) for lang in SUPPORTED_LANGUAGES: jwt_mac = testing_servers.jwt_mac(lang, keyset.SerializeToString()) compact = jwt_mac.compute_mac_and_encode(raw_jwt) self.assertEqual(decode_kid(compact), 'my kid')
def test_jwt_mac_does_not_sets_kid_for_raw_templates(self, template_name): key_template = supported_key_types.KEY_TEMPLATE[template_name] keyset = testing_servers.new_keyset('cc', key_template) raw_jwt = jwt.new_raw_jwt(without_expiration=True) for lang in SUPPORTED_LANGUAGES: jwt_mac = testing_servers.jwt_mac(lang, keyset) compact = jwt_mac.compute_mac_and_encode(raw_jwt) self.assertIsNone(decode_kid(compact))
def test_mac_success(self, key_template): keyset_handle = tink.new_keyset_handle(key_template) jwt_hmac = keyset_handle.primitive(jwt.JwtMac) token = jwt.new_raw_jwt(issuer='issuer', subject='subject') compact = jwt_hmac.compute_mac_and_encode(token) output_token = jwt_hmac.verify_mac_and_decode(compact, jwt.new_validator()) self.assertEqual(output_token.issuer(), token.issuer()) self.assertEqual(output_token.subject(), token.subject())
def test_empty_has_returns_false(self): token = jwt.new_raw_jwt() self.assertFalse(token.has_issuer()) self.assertFalse(token.has_subject()) self.assertFalse(token.has_jwt_id()) self.assertFalse(token.has_audiences()) self.assertFalse(token.has_expiration()) self.assertFalse(token.has_issued_at()) self.assertFalse(token.has_not_before())