As of 0.56.0 release of django-allauth (2023-09-07) the support for Multi-Factor Authentication (MFA) has been added.

This is great news for the Django developer as it allows to easily add MFA to your applications, but the documentation is still a bit sparse, and it appears that the feature is not widely known yet.

In this article, I will show you how to add and configure MFA to your Django apps in under 5 minutes.

MFA Overview

Multi-factor authentication (MFA) adds an extra layer of security to your Django application by requiring users to verify their identity using the password and a second factor, such as a phone or a hardware token, this significantly reduces the risk of unauthorized access, even if attackers compromise the password of a user or an admin.

There are three common factors used for authentication:

  • Something you know: Password, PIN, security questions.
  • Something you have: Phone, hardware token, security key.
  • Something you are: Fingerprint, facial recognition.

While SMS messages were once popular, their vulnerability to SIM swapping attacks makes them less secure. Consider these more robust options:

  • Authenticator apps: Google Authenticator, Authy, Microsoft Authenticator (TOTP or HOTP based).
  • Hardware tokens: YubiKey, Nitrokey (support various protocols like U2F, FIDO2).

Django Allauth and MFA

Django Allauth provides built-in support for MFA using the allauth.account.adapter.DefaultAccountAdapter class. However, it currently only supports the authentifactor app, which uses the Time-based One-Time Password (TOTP) algorithm.

Enabling MFA in Django Allauth also make the admin interface MFA compatible, which is a great feature and greatly enhances the security and integrity of your application.

Bonus: Using the Yubikey with Django Allauth

While hardware tokens are not supported out of the box, it is possible to use the Yubikey with the Yubico Authenticator app, which is a great alternative to the Google Authenticator app and allow you to secure your account and admin panel with a hardware token.

How to add MFA to Django Allauth

Step 1: Install django-allauth[mfa]

In order to use MFA with django-allauth, you need to install the django-allauth package with the mfa extra:

pip install django-allauth[mfa]

You also need to make sure that django-allauth version is at least 0.56.0:

pip install django-allauth==0.56.0

Step 2: Add allauth and allauth.mfa to your INSTALLED_APPS

This is not really specified in the documentation, but you need to add allauth (which should already be done) and allauth.mfa to your INSTALLED_APPS in your settings.py:

INSTALLED_APPS = [
    ...
    'allauth', # required
    'allauth.account', # required
    'allauth.socialaccount', # optional
    'allauth.mfa', # Add this line 
    ...
]

Step 3: Override the MFA templates to match your design (optional)

If you followed the cookiecutter-django installation, or you are using your base.html as a base template for all your pages and user accounts, you might want to override the MFA templates to match your design.

You can do so by creating a mfa folder in your templates directory and create the following files:

  • mfa/base_entrance.html with the following content:
{% extends "base.html" %}

<!-- Your custom content here -->
  • mfa/base_manage.html with the following content:
{% extends "base.html" %}

<!-- Your custom content here -->

Also you need to url to the MFA views in your templates, for example:

{% url 'mfa_activate_totp' %}

Step 4: Update the settings (optional)

Django Allauth MFA comes with a few settings that you can override in your settings.py:

# settings.py

# Specifies the adapter class to use, allowing you to alter certain default behaviour.
MFA_ADAPTER = "allauth.mfa.adapter.DefaultMFAAdapter"

# Used to override forms. Defaults to:
MFA_FORMS = {
    'authenticate': 'allauth.mfa.forms.AuthenticateForm',
    'reauthenticate': 'allauth.mfa.forms.AuthenticateForm',
    'activate_totp': 'allauth.mfa.forms.ActivateTOTPForm',
    'deactivate_totp': 'allauth.mfa.forms.DeactivateTOTPForm',
}

MFA_RECOVERY_CODE_COUNT = 10
# The number of recovery codes.

MFA_TOTP_PERIOD = 30
# The period that a TOTP code will be valid for, in seconds.

MFA_TOTP_DIGITS = 6
# The number of digits for TOTP codes.

Step 5: Run the migrations

python manage.py migrate

Conclusion

Adding MFA to your Django application using django-allauth is a great way to enhance the security of your application, it seemlessly integrates with the existing authentication system without much effort.

For the end user, the process is simple and straightforward, in 2024, MFA is a feature that is expected to be present in any web application.

For the administrators, this means that even in the case of a compromised password, the attacker will not be able to access the admin panel without the second factor.