vimalloc/flask-jwt-extended

Feature Request: Allow selective disabling of blocklist check

GrimzEcho opened this issue · 2 comments

It would be helpful to be able to provide an argument to the @jwt_required() decorator that would disable the blocklist verification for a given route.

This (or another workaround) is needed to be fully compliant with RFC 7009 - OAuth 2.0 Token Revocation. Specifically, the RFC states, "The authorization server responds with HTTP status code 200 if the token has been revoked successfully or if the client submitted an invalid token.".

The RFC also recommends (via should language), that if the auth server supports access token revocation, then it should revoke any access tokens associated with a refresh token when it receives a refresh token revocation request. The simplest way to achieve this is for the server to store the access and refresh tokens upon user login.

Such a schema means that the blocklist becomes more of an allow-list, where a token is considered revoked if it does not appear in the list or table of current access tokens. This approach is mentioned in the jwt-extended documentation as the third option for revoking both access and refresh tokens.

@token_in_blocklist_loader
def is_denied(header, payload):
    return payload['jti'] not in active_tokens

# ...

@jwt_required(verify_type=False)
def logout():
    # look for an entry in active_tokens. If it exists, delete it.
    # either way, return a 200
   token_entry = active_tokens.find_by_token(get_jwt())
   if token_entry:
       token_entry.remove()
    return {'message': 'Logout successful'}

The problem is that the method logic will never run if an invalid token is sent since jwt-extended will run the revocation check, then nvoke the appropriate error handler if the token isn't recognized. Additionally, valid tokens that were previously revoked will also result in an error response (for instance if the user logs out twice in a row using the same access/refresh token, the second attempt will produce an error).

At the same time, an error should be thrown if no token is provided (and get_jwt() doesn't function without @jwt_required()).

The simplest solution would be to optionally bypass the revocation check when adding the decorator. Something like @jwt_required(verify_type=False, skip_revocation_check=True).

There are other workarounds, such as not using the jwt_required decorator on the logout/revoke route (and instead doing manual validation of the token), or looking at the request object in the blocklist loader, and if it contains a specific URL, always returning False, but both of those are less than ideal.

That seems totally reasonable to me. If you want to take a stab it implementing that functionality and making PR please feel free, otherwise I will look into adding that when time allows!

Thanks!

I tried to implement this request, can you help me with the unittests.