Skip to content
Advertisement

Working outside of application context Flask JWT decorator issue

I am fairly new to Flask applications. While my application works for all the endpoints as expected when I tried to add jwt authorization I encountered this issue. I have tried this solution app.app_context().push() based on some other questions that have been posted.

Any help would be greatly appreciated. I would also like to use the decorator in multiple apis, should I include the token_required function in each one, or best practise would be to be imported?

Error:

Traceback (most recent call last):
  File "C:/Users/Gerasimos/Documents/Python/api_mongo/main.py", line 1, in <module>
    from app import create_app
  File "C:UsersGerasimosDocumentsPythonapi_mongoapp.py", line 2, in <module>
    from users.api import users
  File "C:UsersGerasimosDocumentsPythonapi_mongousersapi.py", line 60, in <module>
    @token_required
  File "C:UsersGerasimosDocumentsPythonapi_mongousersapi.py", line 31, in token_required
    return decorated()
  File "C:UsersGerasimosDocumentsPythonapi_mongousersapi.py", line 29, in decorated
    return jsonify({'message' : 'Token is invalid!'}), 401
  File "C:UsersGerasimosAppDataLocalProgramsPythonPython37-32libsite-packagesflaskjson__init__.py", line 309, in jsonify
    if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] or current_app.debug:
  File "C:UsersGerasimosAppDataLocalProgramsPythonPython37-32libsite-packageswerkzeuglocal.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "C:UsersGerasimosAppDataLocalProgramsPythonPython37-32libsite-packageswerkzeuglocal.py", line 306, in _get_current_object
    return self.__local()
  File "C:UsersGerasimosAppDataLocalProgramsPythonPython37-32libsite-packagesflaskglobals.py", line 51, in _find_app
    raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().  See the
documentation for more information.

My application structure:

main.py

from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

app.py

from flask import Flask
from users.api import users
from auth.api import auth


def create_app(settings_overrides=None):
    app = Flask(__name__)
    configure_settings(app, settings_overrides)
    configure_blueprints(app)
    return app


def configure_settings(app, settings_override):
    app.config.update({
        'DEBUG': True,
        'TESTING': True,
        'JSON_SORT_KEYS': False
    })
    if settings_override:
        app.config.update(settings_override)


def configure_blueprints(app):
    app.register_blueprint(users, url_prefix='/api')
    app.register_blueprint(auth, url_prefix='/api')

usersapi.py

from flask import Blueprint, request, Response, jsonify
from pymongo import MongoClient
import json
from validation.RegistrationValidator import UserSchema
from validation.UpdateUserValidator import UpdateUserSchema
from marshmallow import ValidationError
from functools import wraps
import jwt

client = MongoClient('localhost', 27017)
database = client['python_crud_api']
users_collection = database['users']

users = Blueprint('users', __name__)

SECRET_KEY = "hrtegwfjnvwivmwrhriwcg"


def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        try:
            token = request.headers.get('Authorization')
            data = jwt.decode(token, SECRET_KEY)
            return f(*args, **kwargs)
        except:
            headers = {'Content-Type': 'application/json'}
            return jsonify({'message' : 'Token is invalid!'}), 401
            # Response(json.dumps({"message": "Unauthorized user"}), 401, headers=headers)
    return decorated()


@users.route('/user', methods=['GET'])
@token_required
def get_users():
    headers = {'Content-Type': 'application/json'}

    all_users = users_collection.find()
    result = []
    # When a user is returned the password must not be in the response body
    for user in all_users:
        result.append({'username': user['username'], 'email': user['email']})

    return Response(json.dumps({"Users": result}), status=200, headers=headers)

Advertisement

Answer

return decorated not return decorated() in token_required. Otherwise, you’ll be calling the wrapped function whenever you define a decorated function.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement