Search code examples
pythonaccess-tokenflask-restfulrefresh-tokenflask-jwt-extended

Flask-JWT-Extended: @jwt_refresh_token_required annotation does not work


I have a login resource (/login endpoint), following Oleg Agapov's tutorial:

class UserLogin(Resource):
    def post(self):
        data = parser.parse_args()
        current_user = User.find_by_email(data['email'])

        if not current_user:
            return {'message': 'User {} doesn\'t exist'.format(data['email'])}

        if User.verify_hash(data['password'], current_user.password):
            refresh_token = create_refresh_token(identity = data['email'])
            return {
                'message': 'Logged in as {}'.format(current_user.email),
                'refresh_token': refresh_token
                }
        else:
            return {'message': 'Wrong credentials'}

Calling this endpoint with correct credentials I do get the response back:

{
  "message": "Logged in as test@gmail.com",
  "refresh_token": "eyJ0eXAiOiJKV1.............TheVeryLongRefreshTokenString...........JfkRatZ2NaA72Tl4b9C4-e3d6kXA"
}

Now, I have a test resource on the /secret endpoint:

class SecretResource(Resource):
    @jwt_refresh_token_required
    def get(self):
        return {
            'answer': 42
        }

Calling this endpoint with the refresh_token included as a Bearer header in the request should return:

{
   "answer": 42
}

Without the @jwt_refresh_token_required annotation (without sending any tokens) this is exactly what I get. But I need the annotation to secure my endpoint with some token requirement.

Only it doesn't work. Using the Authentication : Bearer *Refresh_Token* header I only get:

{
   "message": "Internal Server Error"
}

enter image description here

I know access_token should be used for this, but I did not wanted it for its 15 minutes expiration time. I don't see why would it be a problem since we are doing the same to refresh the access_token itself with an endpoint requiring a refresh_token. I can be wrong of course.

This is the snippet from the poject_folder root folder's __init__.py where the revocation is checked:

@jwt.token_in_blacklist_loader
def check_if_token_in_blacklist(decrypted_token):
    jti = decrypted_token['jti']
    return poject_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)

What am I missing here?


Solution

  • As @vimalloc has suggested, I needed to add

    app.config['PROPAGATE_EXCEPTIONS'] = True
    

    while configuring the application object to see the actual error, causing the code to break and return a code 500

    The answer is embarrassingly simple, the token checking callback function in the __init__.py file was referencing itself so I had to remove the project_folder prefix:

    From this:

    @jwt.token_in_blacklist_loader
    def check_if_token_in_blacklist(decrypted_token):
        jti = decrypted_token['jti']
        return poject_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)
    

    To this:

    @jwt.token_in_blacklist_loader
    def check_if_token_in_blacklist(decrypted_token):
        jti = decrypted_token['jti']
        return Model.RevokedTokenModel.is_jti_blacklisted(jti)