pythonflaskflask-jwt-extendeditsdangerous

Use JWT-Extended to produce JSON Web Signatures for user confirmation


I am building a RESTful API for an upcoming project. This needs some kind of user account verification. I implemented a token based confirmation procedure previously using itsdangerous. But I wonder wether I can accomplish the same by using JWT-Extended, as its already part of my app and I want to keep the number of dependencies as low as possible.

Could I just use a normal access_token for that?

I appreciate your help!

Edit:

I implemented the following two methods and they seem to work. I am just not sure, if this is considered good practice.

@blueprint.route('/gen_confirmation_token', methods=['GET'])
@jwt_required
def gen_confirmation_token():
    access_token = create_access_token(identity=get_jwt_identity(), user_claims={"confirm": True}, expires_delta=dt.timedelta(seconds=3600))
    # TODO send a link to mail
    return jsonify({"message": "confirmation token sent"}), 200


@blueprint.route('/confirm/<string:token>', methods=['GET'])
@jwt_required
def confirm_user(token):
    user_identity = get_jwt_identity()
    current_user = User.query.get(user_identity)
    decoded_token = decode_token(token)
    if decoded_token['identity'] == user_identity and decoded_token['user_claims'].get('confirm', False):
        current_user.confirm()
        return jsonify({"message": "user confirmed"}), 200
    return jsonify({"message": "invalid confirmation token"}), 400




Solution

  • EDIT

    Seeing the code you've added, which seems to be working, the nature of my answer changes. I think your solution to the problem would be considered good practice. The main problems you have are security, i.e. no one should be able to create their own token, which the hash value confirms, and the tokens should be personalised in such a way that one and only one person can use them, which the user identity guarantees.


    Since you can encode as much information as you want in a JWT token, you should be able to store the information you need in it as well. I'm not sure what format you were thinking of, but if you were to, for example, store the confirmation step someone still has to reach, you can store something like the following:

    @jwt.user_claims_loader
    def add_confirmation_status_to_token(user):
      """Given an identity, add the confirmation status to the token"""
      return dict(status=user.confirmed_email)
    

    For more information, have a look here