def test_generate_jwt(app, user): # A JWT token is generated for a user and is verifiable SECRET_KEY = app.config["SECRET_KEY"] a_jwt = utils.make_jwt(user) # A JWT token will differ over time: with freeze_time("2020-04-02"): decoded_jwt = jwt.decode(a_jwt, SECRET_KEY, algorithms=utils.JWT_ALGORITHM) a_jwt2 = utils.make_jwt(user) assert a_jwt != a_jwt2 # A JWT has basic JWT and the user uuid. assert set(decoded_jwt.keys()) == set( ["uuid", "exp", "iat", "iss", "max-exp"]) assert decoded_jwt["uuid"] == user.uuid assert utils.verify_jwt(user, a_jwt) # An expired JWT token will not be valid: with freeze_time("2020-06-01"): assert not utils.verify_jwt(user, a_jwt) # A JWT token can't be verified with the wrong secret assert not utils.verify_jwt(user, a_jwt, "bad secret") # A jwt with an expired max-exp is not valid. a_jwt = utils.make_jwt(user, datetime.now()) with freeze_time("2020-04-02"): assert not utils.verify_jwt(user, a_jwt)
def test_decode_jwt(app, user): # A generated token can be decoded a_jwt = utils.make_jwt(user) decoded_jwt = utils.decode_jwt(a_jwt.decode("utf-8")) assert decoded_jwt["uuid"] == user.uuid assert set(decoded_jwt.keys()) == set( ["uuid", "exp", "iat", "iss", "max-exp"]) # A blank string cannot be decoded assert not utils.decode_jwt("") # A random string cannot be decoded assert not utils.decode_jwt("aoeucenet") # A jwt without an id key is not valid: a_jwt = jwt.encode( {}, app.config["SECRET_KEY"], algorithm=utils.JWT_ALGORITHM, ) assert not utils.decode_jwt(a_jwt.decode("utf-8")) # A jwt with an expired max-exp can be decoded a_jwt = utils.make_jwt(user) with freeze_time("2020-04-02"): assert utils.decode_jwt(a_jwt.decode("utf-8")) is not False
def test_refresh(client, user): calling_token = make_jwt(user, TOMORROW).decode("utf-8") calling_jwt = decode_jwt(calling_token) # A non json contenttype returns a 400 result = client.post( "/users/auth/refresh", headers={"Authorization": f"Bearer {calling_token}"}, ) assert result.status_code == 400 # A valid JWT token returns a new token # tokens aren't gauranteed to be unique and will be sub-second...so let a # little time go by to gaurantee a unique JWT is returned by the endpoint. time.sleep(1) result = client.post( "/users/auth/refresh", content_type="application/json", headers={"Authorization": f"Bearer {calling_token}"}, ) result_jwt = decode_jwt(result.json["token"]) assert result.status_code == 200 assert verify_jwt(user, result.json["token"]) assert result.json["token"] != calling_token # its max-exp always equals the calling_token's value assert result_jwt["max-exp"] == calling_jwt["max-exp"]
def test_jwt_required(client, user): # No authorization header returns a 401 result = client.post("/users/auth/refresh", content_type="application/json") assert result.status_code == 401 # A non bearer header returns a 401 result = client.post( "/users/auth/refresh", content_type="application/json", headers={"Authorization": "Basic 123456789"}, ) assert result.status_code == 401 # A badly formatted bearer token returns a 401 result = client.post( "/users/auth/refresh", content_type="application/json", headers={ "Authorization": "Bearer eyJ0e XAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNTkzNjI2MjQ5LCJpc3MiOiJhcHAiLCJpYXQiOjE1OTEwMzQyNDl9.-j5K1xiYx6GzyKoI5UsKnpiCA1vF1D5gBreCUlnm01o" }, ) assert result.status_code == 401 # An badly formatted JWT token returns a 401 result = client.post( "/users/auth/refresh", content_type="application/json", headers={ "Authorization": "Bearer XXXXXXXXXXXKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNTkzNjI2MjQ5LCJpc3MiOiJhcHAiLCJpYXQiOjE1OTEwMzQyNDl9.-j5K1xiYx6GzyKoI5UsKnpiCA1vF1D5gBreCUlnm01o" }, ) assert result.status_code == 401 # A valid JWT that is expired returns a 401 db.session.add(user) db.session.commit() calling_token = make_jwt(user, TOMORROW).decode("utf-8") with freeze_time((TOMORROW + timedelta(days=1)).strftime("%Y-%m-%d")): result = client.post( "/users/auth/refresh", content_type="application/json", headers={"Authorization": f"Bearer {calling_token}"}, ) assert result.status_code == 401 # A valid JWT token for a user that doesn't exist returns a 401 db.session.delete(user) db.session.commit() time.sleep(1) result = client.post( "/users/auth/refresh", content_type="application/json", headers={"Authorization": f"Bearer {calling_token}"}, ) assert result.status_code == 401
def test_refresh_max_exp(client, user): db.session.add(user) db.session.commit() calling_token = make_jwt(user, datetime.now()).decode("utf-8") # Renewing a token that is older than its max-exp returns a 401 with freeze_time("2020-05-06"): result = client.post( "/users/auth/refresh", content_type="application/json", headers={"Authorization": f"Bearer {calling_token}"}, ) assert result.status_code == 401