Getting Started =============== Installation ------------ You can install Flask-HTTPAuth with ``pip``:: pip install flask-httpauth Basic authentication example ---------------------------- The following example application uses HTTP Basic authentication to protect route ``'/'``:: from flask import Flask from flask_httpauth import HTTPBasicAuth from werkzeug.security import generate_password_hash, check_password_hash app = Flask(__name__) auth = HTTPBasicAuth() users = { "john": generate_password_hash("hello"), "susan": generate_password_hash("bye") } @auth.verify_password def verify_password(username, password): if username in users and \ check_password_hash(users.get(username), password): return username @app.route('/') @auth.login_required def index(): return "Hello, {}!".format(auth.current_user()) if __name__ == '__main__': app.run() The function decorated with the ``verify_password`` decorator receives the username and password sent by the client. If the credentials belong to a user, then the function should return the user object. If the credentials are invalid the function can return ``None`` or ``False``. The user object can then be queried from the ``current_user()`` method of the authentication instance. Digest authentication example ----------------------------- The following example uses HTTP Digest authentication:: from flask import Flask from flask_httpauth import HTTPDigestAuth app = Flask(__name__) app.config['SECRET_KEY'] = 'secret key here' auth = HTTPDigestAuth() users = { "john": "hello", "susan": "bye" } @auth.get_password def get_pw(username): if username in users: return users.get(username) return None @app.route('/') @auth.login_required def index(): return "Hello, {}!".format(auth.username()) if __name__ == '__main__': app.run() Token Authentication Example ---------------------------- The following example application uses a custom HTTP authentication scheme to protect route ``'/'`` with a token:: from flask import Flask from flask_httpauth import HTTPTokenAuth app = Flask(__name__) auth = HTTPTokenAuth(scheme='Bearer') tokens = { "secret-token-1": "john", "secret-token-2": "susan" } @auth.verify_token def verify_token(token): if token in tokens: return tokens[token] @app.route('/') @auth.login_required def index(): return "Hello, {}!".format(auth.current_user()) if __name__ == '__main__': app.run() The ``HTTPTokenAuth`` is a generic authentication handler that can be used with non-standard authentication schemes, with the scheme name given as an argument in the constructor. In the above example, the ``WWW-Authenticate`` header provided by the server will use ``Bearer`` as scheme:: WWW-Authenticate: Bearer realm="Authentication Required" The ``verify_token`` callback receives the authentication credentials provided by the client on the ``Authorization`` header. This can be a simple token, or can contain multiple arguments, which the function will have to parse and extract from the string. As with the ``verify_password``, the function should return the user object if the token is valid. In the examples directory you can find a complete example that uses JWS tokens. JWS tokens are similar to JWT tokens. However using JWT tokens would require an external dependency. Using Multiple Authentication Schemes ------------------------------------- Applications sometimes need to support a combination of authentication methods. For example, a web application could be authenticated by sending client id and secret over basic authentication, while third party API clients use a JWS or JWT bearer token. The `MultiAuth` class allows you to protect a route with more than one authentication object. To grant access to the endpoint, one of the authentication methods must validate. In the examples directory you can find a complete example that uses basic and token authentication. User Roles ---------- Flask-HTTPAuth includes a simple role-based authentication system that can optionally be added to provide an additional layer of granularity in filtering accesses to routes. To enable role support, write a function that returns the list of roles for a given user and decorate it with the ``get_user_roles`` decorator:: @auth.get_user_roles def get_user_roles(user): return user.get_roles() To restrict access to a route to users having a given role, add the ``role`` argument to the ``login_required`` decorator:: @app.route('/admin') @auth.login_required(role='admin') def admins_only(): return "Hello {}, you are an admin!".format(auth.current_user()) The ``role`` argument can take a list of roles, in which case users who have any of the given roles will be granted access:: @app.route('/admin') @auth.login_required(role=['admin', 'moderator']) def admins_only(): return "Hello {}, you are an admin or a moderator!".format(auth.current_user()) In the most advanced usage, users can be filtered by having multiple roles:: @app.route('/admin') @auth.login_required(role=['user', ['moderator', 'contributor']]) def admins_only(): return "Hello {}, you are a user or a moderator/contributor!".format(auth.current_user()) Deployment Considerations ------------------------- Be aware that some web servers do not pass the ``Authorization`` headers to the WSGI application by default. For example, if you use Apache with mod_wsgi, you have to set option ``WSGIPassAuthorization On`` as `documented here `_. Deprecated Basic Authentication Options --------------------------------------- Before the ``verify_password`` described above existed there were other simpler mechanisms for implementing basic authentication. While these are deprecated they are still maintained. However, the ``verify_password`` callback should be preferred as it provides greater security and flexibility. The ``get_password`` callback needs to return the password associated with the username given as argument. Flask-HTTPAuth will allow access only if ``get_password(username) == password``. Example:: @auth.get_password def get_password(username): return get_password_for_username(username) Using this callback alone is in general not a good idea because it requires passwords to be available in plaintext in the server. In the more likely scenario that the passwords are stored hashed in a user database, then an additional callback is needed to define how to hash a password:: @auth.hash_password def hash_pw(password): return hash_password(password) In this example, you have to replace ``hash_password()`` with the specific hashing function used in your application. When the ``hash_password`` callback is provided, access will be granted when ``get_password(username) == hash_password(password)``. If the hashing algorithm requires the username to be known then the callback can take two arguments instead of one:: @auth.hash_password def hash_pw(username, password): salt = get_salt(username) return hash_password(password, salt)