def test_create_access_token_with_object(self): # Complex object to test building a JWT from. Normally if you are using # this functionality, this is something that would be retrieved from # disk somewhere (think sqlalchemy) class TestUser: def __init__(self, username, roles): self.username = username self.roles = roles # Setup the flask stuff app = Flask(__name__) app.secret_key = 'super=secret' app.config['JWT_ALGORITHM'] = 'HS256' jwt = JWTManager(app) @jwt.user_claims_loader def custom_claims(user): return {'roles': user.roles} @jwt.user_identity_loader def user_identity_lookup(user): return user.username # Create the token using the complex object with app.test_request_context(): user = TestUser(username='******', roles=['bar', 'baz']) token = create_access_token(identity=user) # Decode the token and make sure the values are set properly token_data = _decode_jwt(token, app.secret_key, app.config['JWT_ALGORITHM']) self.assertEqual(token_data['identity'], 'foo') self.assertEqual(token_data['user_claims']['roles'], ['bar', 'baz'])
def wrapper(*args, **kwargs): token = request.args.get('refresh_token') secret = _get_secret_key() algorithm = get_algorithm() jwt_data = _decode_jwt(token, secret, algorithm) if jwt_data['type'] != 'refresh': raise WrongTokenError( 'Only refresh tokens can access this endpoint') ctx_stack.top.jwt = jwt_data return fn(*args, **kwargs)
def test_get_token_ttl(self): # This is called when using a simplekv backend that supports ttl (such # as redis or memcached). Because I do not want to require having those # installed to run the unit tests, I'm going to fiat that the code for # them works, and manually test the helper methods they call for correctness. # Test token ttl with self.app.test_request_context(): token_str = _encode_refresh_token('foo', 'secret', 'HS256', timedelta(minutes=5)) token = _decode_jwt(token_str, 'secret', 'HS256') time.sleep(2) token_ttl = _get_token_ttl(token).total_seconds() self.assertGreater(token_ttl, 296) self.assertLessEqual(token_ttl, 298) # Test ttl is 0 if token is already expired with self.app.test_request_context(): token_str = _encode_refresh_token('foo', 'secret', 'HS256', timedelta(seconds=0)) token = _decode_jwt(token_str, 'secret', 'HS256') time.sleep(2) token_ttl = _get_token_ttl(token).total_seconds() self.assertEqual(token_ttl, 0)
def test_decode_invalid_jwt(self): with self.app.test_request_context(): # Verify underlying pyjwt expires verification works with self.assertRaises(jwt.ExpiredSignatureError): token_data = { 'exp': datetime.utcnow() - timedelta(minutes=5), } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing jti with self.assertRaises(JWTDecodeError): token_data = { 'exp': datetime.utcnow() + timedelta(minutes=5), 'identity': 'banana', 'type': 'refresh' } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing identity with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'refresh' } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing type with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing fresh in access token with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'access', 'user_claims': {} } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Bad fresh in access token with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'access', 'user_claims': {}, 'fresh': 'banana' } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing user claims in access token with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'access', 'fresh': True } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Bad user claims with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'access', 'fresh': True, 'user_claims': 'banana' } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Bad token type with self.assertRaises(JWTDecodeError): token_data = { 'jti': 'banana', 'identity': 'banana', 'exp': datetime.utcnow() + timedelta(minutes=5), 'type': 'banana', 'fresh': True, 'user_claims': 'banana' } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') # Missing and bad csrf tokens self.app.config['JWT_TOKEN_LOCATION'] = 'cookies' self.app.config['JWT_COOKIE_CSRF_PROTECTION'] = True with self.app.test_request_context(): now = datetime.utcnow() with self.assertRaises(JWTDecodeError): token_data = { 'exp': now + timedelta(minutes=5), 'iat': now, 'nbf': now, 'jti': 'banana', 'identity': 'banana', 'type': 'refresh', } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256') with self.assertRaises(JWTDecodeError): token_data = { 'exp': now + timedelta(minutes=5), 'iat': now, 'nbf': now, 'jti': 'banana', 'identity': 'banana', 'type': 'refresh', 'csrf': True } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') _decode_jwt(encoded_token, 'secret', 'HS256')
def test_decode_jwt(self): # Test decoding a valid access token with self.app.test_request_context(): now = datetime.utcnow() now_ts = calendar.timegm(now.utctimetuple()) token_data = { 'exp': now + timedelta(minutes=5), 'iat': now, 'nbf': now, 'jti': 'banana', 'identity': 'banana', 'fresh': True, 'type': 'access', 'user_claims': { 'foo': 'bar' }, } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') data = _decode_jwt(encoded_token, 'secret', 'HS256') self.assertIn('exp', data) self.assertIn('iat', data) self.assertIn('nbf', data) self.assertIn('jti', data) self.assertIn('identity', data) self.assertIn('fresh', data) self.assertIn('type', data) self.assertIn('user_claims', data) self.assertEqual(data['exp'], now_ts + (5 * 60)) self.assertEqual(data['iat'], now_ts) self.assertEqual(data['nbf'], now_ts) self.assertEqual(data['jti'], 'banana') self.assertEqual(data['identity'], 'banana') self.assertEqual(data['fresh'], True) self.assertEqual(data['type'], 'access') self.assertEqual(data['user_claims'], {'foo': 'bar'}) # Test decoding a valid refresh token with self.app.test_request_context(): now = datetime.utcnow() now_ts = calendar.timegm(now.utctimetuple()) token_data = { 'exp': now + timedelta(minutes=5), 'iat': now, 'nbf': now, 'jti': 'banana', 'identity': 'banana', 'type': 'refresh', } encoded_token = jwt.encode(token_data, 'secret', 'HS256').decode('utf-8') data = _decode_jwt(encoded_token, 'secret', 'HS256') self.assertIn('exp', data) self.assertIn('iat', data) self.assertIn('nbf', data) self.assertIn('jti', data) self.assertIn('identity', data) self.assertIn('type', data) self.assertEqual(data['exp'], now_ts + (5 * 60)) self.assertEqual(data['iat'], now_ts) self.assertEqual(data['nbf'], now_ts) self.assertEqual(data['jti'], 'banana') self.assertEqual(data['identity'], 'banana') self.assertEqual(data['type'], 'refresh')