Manually validate flask-extended-jwt's access token
Asked Answered
E

1

10

I have a SPA app that contains an form with an upload file field. I have a rest API whose endpoints are protected via flask-extended-jwt JWT. To authenticate the REST endpoints I use @jwt_required. I want to authenticate the upload request as well.

Because of the client side I can't add an Authorization Bearer header so I thought to add the access token as a hidden field when submitting the form.

What is the best way to manually validate the JWT access token after I read it from the form?

class Upload(Resource):

def post(self):
    #TODO: check for access token
    access_token = None
    if 'access_token' in request.form and request.form['access_token']:
        access_token = request.form['access_token']
    else:
        message = json.dumps({'message': 'Invalid or missing token', 'success': False})
        return Response(response=message, status=401, mimetype='text/plain')

    if access_token:
        #TODO: validate_token(access_token)

Thank you

Eliason answered 20/8, 2018 at 14:6 Comment(0)
L
7

Author of flask-jwt-extended here. That's a great question. There is currently no supported way to do that in the extension, the grabbing the token from the request and decoding it are tightly coupled together. This would be hard to de-couple because there is a lot of conditional things that are going on when the full decode chain runs. For example, checking the CSRF value only if the request is sent in via a cookie, or differentiating between an access and refresh token for the sake of the blacklisting feature.

A generalized function could be created, it's signature would look something like decode_and_verify_jwt(encoded_token, is_access_token=True, check_csrf=False). However, this would complicate the rest of the code in flask_jwt_extended and be a rather confusing function to use for the general case.

I think in this case it would be easier just to add a fourth lookup in the extension, so you could use something like:

app.config['JWT_TOKEN_LOCATION'] = ['headers', 'forms']
app.config['JWT_FORM_KEY'] = 'access_token'
# Use the rest of the application normally

If you want to make a ticket on the github page so I can track this, I would be happy to work on it.

Luncheon answered 23/8, 2018 at 3:48 Comment(2)
Very nice explanation. The solution I found until now is to use the decode_token method. Based on docs, it will return a decoded token (a python dict) or as I tested will raise an exception. Still your solution is more generic.Eliason
Yes, that will decode the jwt. Just be aware that all the other callbacks and everything based on them (such as the user loader, get_jwt_identity, etc) will not be functional in that endpoint.Luncheon

© 2022 - 2024 — McMap. All rights reserved.