1

I'm trying flask for the first time and I'm trying to create a rest api with token-based authentication.

Everything's going fine except that I cannot customize the unauthorized response returned by @auth_token_required which is this default message:

Unauthorized

The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.

I would like it to return a json response which may look something like:

{
    "code": 401,
    "message": "Unauthorized message"
}

So far I have tried overriding unauthorized_handler using:

@app.login_manager.unauthorized_handler
def unauthorized():
    // code goes here

But it doesn't seem to work for @auth_token_required decorator.

DigitalDouble
  • 1,747
  • 14
  • 26

3 Answers3

1

Refering to the response by pip, Flask Security internally uses flask login for its implementation callback.Hence when we register a callback handler with Flask security, we get call stack exceeded response.

app.security.unauthorized_handler(unauth_handler)

Hence instead please register with Flask login

app.login_manager.unauthorized_handler(unauth_handler)

Hope this helps.

Manojak
  • 149
  • 2
  • 3
  • 10
0

Here is the code I have; it seems to work!

import json

from flask import Reponse


def unauth_handler():
    return Response(json.dumps({'unauthorized': True}), 401)

app.security.unauthorized_handler(unauth_handler)

Here is a more complete example of where this is being called just in case that has something to do with the error below.

def setup_app(app):
    config(app)

    # database init, allows the DB to be available in core but setup per application.
    db.init_app(app)

    # bcrypt, again available from core.
    bcrypt.init_app(app)

    # setup assets
    app.assets_env = Environment(app)

    # login system
    app.user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    app.security = security.init_app(app, app.user_datastore)

    def unauth_handler():
        return Response(ejson.dumps({'unauthorized': True}), 401)

    app.security.unauthorized_handler(unauth_handler)

    logger(app)
    jinja_filters(app)
    assets(app)
    modules(app)

And then I pass in the app into the setup function in init.

pip
  • 453
  • 2
  • 13
0

updating the above answer

from flask import response, jsonify
from flask_security.decorators import _get_unauthorized_response

user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security()
security_state = security.init_app(app, user_datastore)

def unauth_handler():
    if request.is_json:
        return jsonify({'status': False, 'message': 'Unauthorized!'}), 401, {'Content-Type': 'application/json'}
    else:
        return _get_unauthorized_response()

security_state.unauthorized_handler(unauth_handler)