Search code examples
pythonrestflaskrestful-authenticationflask-restful

Flask RESTful Destroy User Token


I am setting up a Flask-RESTful service and have user authentication working. The method that I'm using is:

def generate_auth_token(username, expiration=600):
    gen_serial = Serializer(secret_key, expires_in=expiration)
    return gen_serial.dumps({'username': username})

I pass the token to the user as follows:

class token(Resource):
    decorators = [auth.login_required]
    def post(self):
        username = g.user
        return_token = generate_auth_token(username)
        return {'token':return_token.decode()}, 200

And the token is then verified as such so that it does not need to be stored server side:

def verify_auth_token(auth_token):
    serial = Serializer(secret_key)
    try:
        data = serial.loads(auth_token)
    except SignatureExpired:
        return None 
    except BadSignature:
        return None 
    serial_user = data['username']
    return serial_user

This seems to work well, however I am unsure how to logout the user before the expiration is expired without storing the token serverside. My thought was to pass back a garbage token when the user elects to logout, but I don't think this is an elegant or secure solution.

Any tips would be really helpful!


Solution

  • Rather than a garbage token simply encode no data:

    def generate_auth_token(username=None, expiration=600):
        gen_serial = Serializer(secret_key, expires_in=expiration)
        data = {'username': username} if username is not None else {}
        return gen_serial.dumps(data)
    

    Then you can have an invalidate endpoint that requires a login and returns a token without a username:

    def invalidate(self):
        return_token = generate_auth_token()
        return {'token':return_token.decode()}, 200
    

    At that point, you can just handle the possibly missing username field:

    def verify_auth_token(auth_token):
        serial = Serializer(secret_key)
        try:
            data = serial.loads(auth_token)
        except SignatureExpired:
            return None 
        except BadSignature:
            return None 
        serial_user = data.get('username')
        return serial_user