Flask HTTP Basicauth - How does it work?
I'm trying to create a login system using Flask and HTTP Basic Auth. My question is, is it my responsibility to provide user information from databases, or does basicauth create and access those databases for me? If it doesn't, what can I use to do that?
Werkzeug can decode the Basic Authorization header for you, into the username and password. The rest is up to you to see what you want to do with that information.
The request.authorization
attribute returns a Authorization
object. For basic authentication headers, only username
and password
are set.
A project like Flask-Login
can help you manage more complex logins with Basic Authorization, and tie that in with a user model you provide. That model can be stored in a database or anything else you so desire.
And you can look at Flask-Security for a more fully integrated security package that uses Flask-Login and other packages to provide Basic Authentication and session based logins.
The Flask-HTTPAuth extension (shameless plug, I'm the author) simplifies the implementation of HTTP Basic Auth. Instead of working with the request.authorization
data directly you set up callback functions where you plug the authentication logic.
Regarding your database question, Flask-HTTPAuth makes no assumptions about how your users are stored. You have to provide the logic that retrieves users and validates passwords.
Werkzeug parses the Authorization
header into request.authorization
, which is an Authorization
object.
For security reasons, a browser might only send this header if it first received a 401 error response with a WWW-Authenticate
header set. A different client, such as the requests library, will send the header directly.
The simplest demonstration of this is a decorator that checks request.authorization
and returns a 401 response if it's not set, or if the credentials were invalid. In practice, you should use an extension such as Flask-Login or Flask-HTTPAuth to manage this.
from functools import wraps
from flask import request
def login_required(f):
@wraps(f)
def wrapped_view(**kwargs):
auth = request.authorization
if not (auth and check_auth(auth.username, auth.password)):
return ('Unauthorized', 401, {
'WWW-Authenticate': 'Basic realm="Login Required"'
})
return f(**kwargs)
return wrapped_view
@app.route('/secret')
@login_required
def secret():
return f'Logged in as {request.authorization.username}.'
import requests
response = requests.get('http://127.0.0.1:5000/secret', auth=('world', 'hello'))
print(response.text)
# Logged in as world.