2

I've been working with some of Miguel Grinberg's auth tutorials and have come across an issue using flask_httpauth's HTTPBasicAuth decorators. Whenever I use one of them on a function I get an error stating that the decorator is missing required positional argument f. It was my understanding that the function beneath the decorator was implicitly passed to the decorator function as an argument. Am I wrong? I'm using Python 3.5.

My views file looks like this:

from mymodule import app, api, auth
from flask import abort, request, jsonify, g, url_for
from mymodule.users.models import User


@auth.verify_password
def verify_password(username_or_token, password):
    # first try to authenticate by token
    user = User.verify_auth_token(username_or_token)
    if not user:
        # try to authenticate with username/password
        user = User.query.filter_by(username=username_or_token).first()
        if not user or not user.verify_password(password):
            return False
    g.user = user
    return True


@app.route('/api/users', methods=['POST'])
def new_user():
    username = request.json.get('username')
    password = request.json.get('password')
    if username is None or password is None:
        abort(400)    # missing arguments
    if User.query.filter_by(username=username).first() is not None:
        abort(400)    # existing user
    user = User(username=username)
    user.hash_password(password)
    db.session.add(user)
    db.session.commit()
    return (jsonify({'username': user.username}), 201,
            {'Location': url_for('get_user', id=user.id, _external=True)})


@app.route('/api/users/<int:id>')
def get_user(id):
    user = User.query.get(id)
    if not user:
        abort(400)
    return jsonify({'username': user.username})


@app.route('/api/token')
@auth.login_required
def get_auth_token():
    token = g.user.generate_auth_token(600)
    return jsonify({'token': token.decode('ascii'), 'duration': 600})


@app.route('/')
@auth.login_required
def index():
    return "Hello, %s!" % g.current_user


@app.route('/api/resource')
@auth.login_required
def get_resource():
    return jsonify({'data': 'Hello, %s!' % g.user.username})

and my init file (where auth, app, api, etc are imported from) looks like this:

import logging
from logging.handlers import RotatingFileHandler
from flask_sqlalchemy import SQLAlchemy
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth
from flask_restful import Api
from itsdangerous import TimedJSONWebSignatureSerializer as JWT

from flask import Flask

app = Flask(__name__)

"""
Database Config
"""
app.config['SQLALCHEMY_DATABASE_URL'] = 'sqlite:////db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

app.config['SECRET_KEY'] = 'top secret!'

handler = RotatingFileHandler('logfile.log', maxBytes=10000, backupCount=1)
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)

api = Api(app)
db = SQLAlchemy(app)
auth = HTTPBasicAuth
jwt = JWT(app.config['SECRET_KEY'], expires_in=3600)

import mymodule.users.views

Any idea why this isn't working for me? The exact error runs like this:

File "/.../users/views.py", line 14, in <module>
    @auth.verify_password
TypeError: verify_password() missing 1 required positional argument: 'f'
JwM
  • 354
  • 2
  • 15

1 Answers1

4

Change this:

auth = HTTPBasicAuth

to this:

auth = HTTPBasicAuth()
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152