Fingerprint-based authentication and Authorization in Python(Django) web applications

sirneij

John Owolabi Idogun

Posted on June 8, 2021

Fingerprint-based authentication and Authorization in Python(Django) web applications

Passwords, as great as they have been, have some setbacks, both for users and developers. Applications users tend to always worry about passwords being stolen by phishing tools, or their passwords being leaked online when used on compromised websites. Aside this, they also have to worry about creating and remembering passwords even in contemporary times when password management tools are prevalent. At the flip side of it, Developers have to worry about all the complications of passing passwords through systems and safely storing them in databases. All these, among others, prompted W3C and FIDO as well as other tech juggernauts such as Google, Mozilla, Microsoft and Yubico to put forward a new authentication paradigm which allows biometric and other cryptographic means to authenticate users. It is aptly known as WebAuthn.

Modern browsers support this awesome technology and there are a couple of its implemetations in various major programming languages and web frameworks. However, this series of tutorials will only focus on implementing it in a Django application using a wonderful django package, django-mfa2 which utilizes python-fido2 under the hood.

The full code for this article can be accessed on

GitHub logo Sirneij / django_mfa2_example

A simple fingerprint-based authentication and authorization application using django-mfa2

django_mfa2_example

Fingerprint-based authentication and authorization system in Python (Django). This can be integrated with e-voting systems and other applications that should be very secure.

A walk-through of this repository can be found on dev.to in this tutorial-like article Fingerprint-based authentication and authorization in Python(Django) web applications. This example application uses Django-mfa2 to implement a password-less fingerprint-based authentication and authorization system. It's live and can be accessed here.

Run locally

  • clone this report:
    git clone https://github.com/Sirneij/django_mfa2_example.git
    
  • create and activate virtual environment (I used pipenv but you can stick with venv, virtualenv or poetry):
    pipenv shell
    pipenv install
    
  • makemigrations and migrate:
    python manage.py makemigrations
    python manage.py migrate
    
  • optionally, createsuperuser:
    python manage.py createsuperuser
    
and is live here. In the live version, your username must start with CPE.

Below are the links to other articles in this series:

Please note that we won't be that particular about the looks of the application. In fact, it was built using bootstrap5's example templates. It is assumed you have atleast gone through Django tutorial or are familiar with Django.

Now, let's get started.

Fire up your terminal and navigate or create the directory you will be working on. As for me, I have already created django-mfa-example and have activated my virtual environment using pipenv.

Install django and django-mfa2:

┌──(sirneij@sirneij)-[~/Documents/Projects/django-mfa2-example]
└─$[sirneij@sirneij django-mfa2-example]$ pipenv install django django-mfa2
Enter fullscreen mode Exit fullscreen mode

Create a django project with the name you like. I will stick with django_mfa_example.

┌──(sirneij@sirneij)-[~/Documents/Projects/django-mfa2-example]
└─$[sirneij@sirneij django-mfa2-example]$ django-admin startproject django_mfa_example .
Enter fullscreen mode Exit fullscreen mode

Notice the . at the end of the command. This prevents django from creating extra folder to hold the project.

You should now have this file structure:

 └──   django_mfa2_example/ 
 │  ├────   asgi.py  
 │  ├────   __init__.py  
 │  ├────   settings.py  
 │  ├────   urls.py  
 │  └────   wsgi.py  
 ├──   manage.py  
 ├──   Pipfile  
 ├──   Pipfile.lock  
 ├──   Procfile 
Enter fullscreen mode Exit fullscreen mode

Next, scaffold a django application. I call it accounts. Any name is fine, just prefer that.

┌──(sirneij@sirneij)-[~/Documents/Projects/django-mfa2-example]
└─$[sirneij@sirneij django-mfa2-example]$ python manage.py startapp accounts
Enter fullscreen mode Exit fullscreen mode

Proceed to your project's INSTALLED_APPS in settings.py file and append mfa and accounts.apps.AccountsConfig to it as shown below:

# django_mfa_example > settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mfa', #add this for django-mfa2

    'accounts.apps.AccountsConfig', #your local app
]
Enter fullscreen mode Exit fullscreen mode

Configure your STATICFILES_DIRS, and STATIC_ROOT. Create static and templates folders at the root of the application and connect them appropriately in your settings.py file.

If you are lost, check the code on github to guide you.

In your accounts app, create a urls.py file and link it to your project's urls.py. Also, to use django-mfa2, you are required to add it to your project's urls.py.

from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
import mfa
import mfa.TrustedDevice

urlpatterns = [
    path('admin/', admin.site.urls),
    path('mfa/', include('mfa.urls')), #required to use mfa
    path('devices/add/', mfa.TrustedDevice.add,name="mfa_add_new_trusted_device"), #required if you intend adding some devices
    path("", include('accounts.urls', namespace='accounts')) #include accounts with namespace
]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)
Enter fullscreen mode Exit fullscreen mode

This line:

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)
Enter fullscreen mode Exit fullscreen mode

instructs django to serve the static files during development only or when DEBUG is True.

Now, let's add some mfa specific configurations to our project's settings.py

MFA_UNALLOWED_METHODS=()   # Methods that shouldn't be allowed for the user
MFA_LOGIN_CALLBACK="accounts.views.login_user_in"            # A function that should be called by username to login the user in session
MFA_RECHECK=True           # Allow random rechecking of the user
MFA_RECHECK_MIN=10         # Minimum interval in seconds
MFA_RECHECK_MAX=30         # Maximum in seconds
MFA_QUICKLOGIN=True        # Allows quick login for returning users

TOKEN_ISSUER_NAME="django_mfa2_example"      #TOTP Issuer name, this should be your project's name

if DEBUG:
  U2F_APPID="https://localhost"    #URL For U2F
  FIDO_SERVER_ID=u"localhost"      # Server rp id for FIDO2, it is the full domain of your project
else:
  U2F_APPID="https://django-mfa2-example.herokuapp.com"    #URL For U2F
  FIDO_SERVER_ID=u"django-mfa2-example.herokuapp.com"      # Server rp id for FIDO2, it is the full domain of your project

FIDO_SERVER_NAME=u"django_mfa2_example"
MFA_REDIRECT_AFTER_REGISTRATION = 'accounts:index'
MFA_SUCCESS_REGISTRATION_MSG = 'Your keys have successfully been created! You '
Enter fullscreen mode Exit fullscreen mode

Since we would like to make the application production-ready, notice the inclusion of these lines:

if DEBUG:
  U2F_APPID="https://localhost"    #URL For U2F
  FIDO_SERVER_ID=u"localhost"      # Server rp id for FIDO2, it is the full domain of your project
else:
  U2F_APPID="https://django-mfa2-example.herokuapp.com"    #URL For U2F
  FIDO_SERVER_ID=u"django-mfa2-example.herokuapp.com"      # Server rp id for FIDO2, it is the full domain of your project
Enter fullscreen mode Exit fullscreen mode

If you are going to have a different domain name, edit the else block accordingly.

To wrap up this part, let's include some basic settings to our accounts application.
First off, populate accounts/urls.py with the following:

from django.urls import path

app_name = 'accounts'

urlpatterns = []

Enter fullscreen mode Exit fullscreen mode

app_name = 'accounts' is necessary since we added namespace='accounts' in our project's urls.py file. Nothing spectacular aside that.

It's a best practice to override django's default User model, therefore open up accounts/models.py file and paste the following in:

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    display_name = models.CharField(max_length=32)

Enter fullscreen mode Exit fullscreen mode

In the code, we are inheriting from AbstractUser and appending diaplay_name field to our User table. To know about the reason I used AbstractUser and not AbstractBaseUser, read this Vitor Freitas's article and Michael Herman's Creating a Custom User Model in Django.

To make Django aware of this new user model, proceed to your settings.py file and add:

AUTH_USER_MODEL = 'accounts.User'
Enter fullscreen mode Exit fullscreen mode

If your application name isn't accounts and/or your new model isn't User, change the line above to:

AUTH_USER_MODEL = 'application_name.new_user_model_name'
Enter fullscreen mode Exit fullscreen mode

You can now run migrations to ensure no mistakes have been made.

Note that the complete code for this application is on

GitHub logo Sirneij / django_mfa2_example

A simple fingerprint-based authentication and authorization application using django-mfa2

django_mfa2_example

Fingerprint-based authentication and authorization system in Python (Django). This can be integrated with e-voting systems and other applications that should be very secure.

A walk-through of this repository can be found on dev.to in this tutorial-like article Fingerprint-based authentication and authorization in Python(Django) web applications. This example application uses Django-mfa2 to implement a password-less fingerprint-based authentication and authorization system. It's live and can be accessed here.

Run locally

  • clone this report:
    git clone https://github.com/Sirneij/django_mfa2_example.git
    
  • create and activate virtual environment (I used pipenv but you can stick with venv, virtualenv or poetry):
    pipenv shell
    pipenv install
    
  • makemigrations and migrate:
    python manage.py makemigrations
    python manage.py migrate
    
  • optionally, createsuperuser:
    python manage.py createsuperuser
    



in case you run into problems.

The next part can be accessed using Fingerprint-based authentication and Authorization in Python(Django) web applications - Second part.

Outro

Enjoyed this article? I'm a Software Engineer and Technical Writer actively seeking new opportunities, particularly in areas related to web security, finance, healthcare, and education. If you think my expertise aligns with your team's needs, let's chat! You can find me on LinkedIn and Twitter.

If you found this article valuable, consider sharing it with your network to help spread the knowledge!

References

💖 💪 🙅 🚩
sirneij
John Owolabi Idogun

Posted on June 8, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related