Tech Monger

Programming, Web Development and Computer Science.

Skip to main content| Skip to information by topic

Flask Basic User Login without Database

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 as hunter2 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 Unauthorizedand sending http header WWW-Authenticate like below.
    WWW-Authenticate : Basic
    It would also prompt client browser to open sign in pop up to pass input username and password.
  • Client must send Authorization header containing colon separated and base 64 encoded username -password like below.

    Authorization : Basic am9objpodW50ZXIy

    Note that username john and password hunter2 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.

Tagged Under : Flask Python Web