How to implement login required decorator in Flask How to implement login required decorator in Flask flask flask

How to implement login required decorator in Flask


Have a look at the official flask docs regarding decorators:https://flask.palletsprojects.com/en/1.1.x/patterns/viewdecorators/ or the python docs https://www.python.org/dev/peps/pep-0318/ as well.

Your decorator should look something like:

from functools import wrapsfrom flask import abortimport jwtdef authorize(f):    @wraps(f)    def decorated_function(*args, **kws):            if not 'Authorization' in request.headers:               abort(401)            user = None            data = request.headers['Authorization'].encode('ascii','ignore')            token = str.replace(str(data), 'Bearer ','')            try:                user = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])['sub']            except:                abort(401)            return f(user, *args, **kws)                return decorated_function

... and then in your app.py you may have:

@app.route('/api/game', methods=['POST'])@authorizedef create(user):    data = json.loads(request.data)    ....

In this particular case I have used JWT as token and your token can be different respectively the decoding of the token can be your custom implementation, but the basic mechanisms are pretty much as on the example above.


Given that each subsequent request will contain the API token, the decorator should do the following

  • Accept a generic request. You can use *args and **kargs for that
  • Extract the token from the header and compare it with the token stored in db (not Redis, but wherever the token generated is stored in the backend)
  • If authenticated, the *args and **kargs should be passed on to the decorated function
  • The output of the decorated function should then be returned as is
  • If the authentication failed, an error message should be returned.

For explanation on decorators, check out this link:http://thecodeship.com/patterns/guide-to-python-function-decorators/


I would place the following decorator function in somewhere common

def validate_api_token(validation_func):    def decorator(f):        @wraps(f)        def decorated_function(*args, **kws):            api_token = request.headers.get('Authorization')            is_valid_api_token = validation_func(api_token)            if is_valid_api_token:                return f(*args, **kws)            return 'Invalid API Token', 401        return decorated_function    return decorator

For small POC flask apps, if you're ok with storing the tokens in a non-versioned file, the following can work:

# tokens are read from a non-versioned `.tokens` file and loaded into a setapi_tokens = load_api_tokens() def simple_api_token_validation(api_token):    return api_token in api_tokens@app.route("/v1/my/secret/function", methods=['POST'])@validate_api_token(simple_api_token_validation)def my_secret_function():   body = request.get_json()   # ...

Another simple option is to query against a database (e.g. redis):

redis_session = Redis(host=REDIS_HOST, password=REDIS_PASSWORD)def redis_api_token_validation(api_token):    if not api_token:        return False    api_token_hash = hashlib.sha256(api_token.encode()).hexdigest()    return redis_session.exists(f'api:tokens:{api_token_hash}')@app.route("/v1/my/secret/function", methods=['POST'])@validate_api_token(redis_api_token_validation)def my_secret_function():   body = request.get_json()   # ...

Best IMO as @Velin answered is to use jwt to validate the token