1

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?

MattSom
  • 2,097
  • 5
  • 31
  • 53
  • 1
    See this for why you are seeing a 500 error instead of a 400 one: https://github.com/vimalloc/flask-jwt-extended/issues/86#issuecomment-519347386. Getting the 400 error back should tell you what actually went wrong with validating the token. – vimalloc Oct 31 '19 at 03:27
  • @vimalloc Thanks for the response. I'm not sure what modifications you are suggesting. Should I only set the error handler with the `jwt._set_error_handler_callbacks(api)` or do I need to return an additional 400 error code in the secret endpoint somehow? – MattSom Oct 31 '19 at 13:05
  • Just the _set_error_handler_callback or PROPAGATE_EXCEPTIONS thing. Flask_jwt_extended should be returning a 400 response with details as to why decoding the token failed, such as if it was missing, expired, etc, but flask restful and rest plus don’t play nicely with that by default. – vimalloc Oct 31 '19 at 13:10
  • I get `@app.errorhandler(NoAuthorizationError) AttributeError: 'Api' object has no attribute 'errorhandler'`. Should I give the Api object or de Flask object as a parameter? – MattSom Oct 31 '19 at 13:56
  • 1
    Oh, it looks like that guide is using flask-restful, not flask-restplus. For flask-restful, you will want to use this (https://github.com/vimalloc/flask-jwt-extended/issues/86#issuecomment-444983119), not the _set_error_handler_callbacks stuff. – vimalloc Oct 31 '19 at 14:01
  • @vimalloc Yes, I forgot to mention that it is flask-restful. Thank you for the helpful response, I've got a detailed stack trace this time so maybe I can look for a specific problem :) – MattSom Oct 31 '19 at 14:25

1 Answers1

0

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)
MattSom
  • 2,097
  • 5
  • 31
  • 53