If you are writing simple and minimalist web application or api using Python and Flask which requires user login without database then you can use HTTP Basic Authentication to authorize user login. This authentication is part of HTTP protocol RFC 7617
and does not require session or cookies for implementation. Client implementation is supported by browsers hence you need not write client side code like html, css and javascript. In this tutorial we will learn how to implement server side code in flask from scratch without using plugin or existing libraries. Also it is strongly advised to understand theory of How Basic Access Authentication Works before we dive into code.
Example Scenario
- Let us say client want to access restricted url end point
/confidential/
on the server. - Server has configured username as
john
and password ashunter2
to authenticate users before rendering restricted url end points. - Whenever client try to access restricted page, server must suggest client to use basic access authentication by returning HTTP
401 Unauthorized
and sending http headerWWW-Authenticate
like below.
It would also prompt client browser to open sign in pop up to pass input username and password.WWW-Authenticate : Basic
-
Client must send
Authorization
header containing colon separated and base 64 encoded username -password like below.Authorization : Basic am9objpodW50ZXIy
Note that username
john
and passwordhunter2
is getting encoded like following.Endoding : Base64Encode('john:hunter2') Output : am9objpodW50ZXIy
Note : Browser will perform this encoding and pass header automatically for users.
- Server should check for
Authorization
header for encoded username and password and should check it against correct credentials. Based on that server should return response.
Example Code
from flask import Flask, request, Response
import base64
app = Flask(__name__)
def check(authorization_header):
username = "john"
password = "hunter2"
encoded_uname_pass = authorization_header.split()[-1]
if encoded_uname_pass == base64.b64encode(username + ":" + password):
return True
@app.route('/confidential/')
def confidential():
authorization_header = request.headers.get('Authorization')
if authorization_header and check(authorization_header):
return "Render confidential page"
else:
resp = Response()
resp.headers['WWW-Authenticate'] = 'Basic'
return resp, 401
Better Code
It is very likely that you would need this authentication for multiple pages hence it make sense to create custom decorator for that purpose.
from flask import Flask, request, Response
import base64
from functools import wraps
app = Flask(__name__)
def check(authorization_header):
username = "john"
password = "hunter2"
encoded_uname_pass = authorization_header.split()[-1]
if encoded_uname_pass == base64.b64encode(username + ":" + password):
return True
def login_required(f):
@wraps(f)
def decorated(*args, **kwargs):
authorization_header = request.headers.get('Authorization')
if authorization_header and check(authorization_header):
return f(*args, **kwargs)
else:
resp = Response()
resp.headers['WWW-Authenticate'] = 'Basic'
return resp, 401
return f(*args, **kwargs)
return decorated
@app.route('/confidential/')
@login_required
def confidential():
return "Render confidential page"
@app.route('/restricted/')
@login_required
def restricted():
return "Render restricted page."
Security Caveat
Use this authentication only if you have HTTPS
enabled in your flask app. Because credentials are base64 encoded and can easily be read over the insecure network. Bottom line is Do not use it over plaintext HTTP
.
Conclusion
This tutorial is just to understand working of basic authentication but if you want to use it in your project then you should consider using existing plugins or libraries. Because there are other functionalities which are offered by basic access authentication such as configuring realm
to implement access control over certain part of the application or using specific character set encoding by setting charset
which we have not implemented above. Also for full fledged multi user web application you should consider building simple user authentication with database.