Digital security is more critical than ever and protecting web applications against unauthorized access is a priority for developers and businesses alike.

Django offers robust security features out of the box. However, as cyber threats evolve, additional layers of security like Multi-Factor Authentication (MFA) become essential.

This is where Django-MFA2 comes into play— it is designed to integrate MFA into Django applications.

In this article, we will explore what Django-MFA2 is, how it works, and why it's a valuable tool for enhancing application security.

What is Django-MFA2?

Django-MFA2 is an open-source Django package that provides an extra layer of security by requiring users to verify their identity using multiple authentication methods.

Traditionally, web applications rely on single-factor authentication, typically a username and password.

However, Django-MFA2 introduces a secondary verification step through various forms like OTPs (One Time Passwords), U2F (Universal 2nd Factor) devices, and TOTP (Time-based One Time Passwords).

Excited to dive deeper into the world of Python programming? Look no further than my latest ebook, "Python Tricks - A Collection of Tips and Techniques".

Get the eBook

Inside, you'll discover a plethora of Python secrets that will guide you through a journey of learning how to write cleaner, faster, and more Pythonic code. Whether it's mastering data structures, understanding the nuances of object-oriented programming, or uncovering Python's hidden features, this ebook has something for everyone.

Key Features of Django-MFA2

Here are some of the key features of Django-MFA2:

  • Versatility in Authentication Methods: Django-MFA2 supports multiple forms of authentication, including OTPs sent via email or SMS, TOTP applications like Google Authenticator or Authy, and hardware tokens like YubiKey.
  • Easy Integration: The package is designed to be seamlessly integrated into existing Django projects without requiring substantial changes to the application structure or database.
  • Customizable and Flexible: Developers can customize Django-MFA2 to fit specific requirements, whether it’s adjusting the authentication flow or modifying the user interface.
  • High-Security Standards: By adding an additional authentication step, Django-MFA2 significantly increases security, reducing the risk of unauthorized access even if a user’s primary password is compromised.

How Django-MFA2 Works

Integrating Django-MFA2 into a Django project involves several key steps:

Installation and Setup

Developers start by installing the Django-MFA2 package using pip and adding it to their project’s settings.

pip install django-mfa2


The package needs to be configured to specify which authentication methods will be available and how they should be implemented.

Add mfa to your INSTALLED_APPS in your Django project's file:


Next, you need to collect the static files belonging to Django-MFA2:

python collectstatic

To include MFA-related URLs in your Django project, modify your file as follows:

from django.urls import include, path
import mfa
from mfa.TrustedDevice import add as add_trusted_device

urlpatterns = [
    path('mfa/', include('mfa.urls')),  # Include MFA URLs for handling MFA processes.
    path('devices/add', add_trusted_device, name="mfa_add_new_trusted_device"),  # Link to add a new trusted device.

After you need to configure the desired authentication methods in the

from django.conf.global_settings import PASSWORD_HASHERS as DEFAULT_PASSWORD_HASHERS #Preferably at the same place where you import your other modules
MFA_UNALLOWED_METHODS=()   # Methods that shouldn't be allowed for the user e.g ('TOTP','U2F',)
MFA_LOGIN_CALLBACK=""      # A function that should be called by username to login the user in session
MFA_RECHECK=True           # Allow random rechecking of the user
MFA_REDIRECT_AFTER_REGISTRATION="mfa_home"   # Allows Changing the page after successful registeration
MFA_SUCCESS_REGISTRATION_MSG = "Go to Security Home" # The text of the link
MFA_RECHECK_MIN=10         # Minimum interval in seconds
MFA_RECHECK_MAX=30         # Maximum in seconds
MFA_QUICKLOGIN=True        # Allow quick login for returning users by provide only their 2FA
MFA_ALWAYS_GO_TO_LAST_METHOD = False # Always redirect the user to the last method used to save a click (Added in 2.6.0).
MFA_RENAME_METHODS={} #Rename the methods in a more user-friendly way e.g {"RECOVERY":"Backup Codes"} (Added in 2.6.0)
MFA_HIDE_DISABLE=('FIDO2',)     # Can the user disable his key (Added in 1.2.0).
MFA_OWNED_BY_ENTERPRISE = FALSE  # Who owns security keys   
PASSWORD_HASHERS += ['mfa.recovery.Hash'] 
RECOVERY_ITERATION = 350000 #Number of iteration for recovery code, higher is more secure, but uses more resources for generation and check...


U2F_APPID="https://localhost"    #URL For U2F
FIDO_SERVER_ID=u"localehost"      # Server rp id for FIDO2, it is the full domain of your project

The provided code snippet showcases various configuration settings related to the Multi-Factor Authentication (MFA) implementation using Django-MFA2:

MFA Configuration Options:

  • MFA_UNALLOWED_METHODS: A tuple listing MFA methods that should not be allowed (e.g., 'TOTP', 'U2F'). This can be used to restrict certain types of authentication methods based on application requirements or security policies.
  • MFA_LOGIN_CALLBACK: A string specifying the callback function name that handles user login sessions after successful MFA verification. This is typically used to integrate MFA more closely with custom authentication flows.
  • MFA_RECHECK: A Boolean value enabling random rechecking of MFA authentication to enhance security by requiring re-verification at random intervals.
  • MFA_REDIRECT_AFTER_REGISTRATION: Specifies the URL name to redirect to after successful MFA registration/setup.
  • MFA_SUCCESS_REGISTRATION_MSG: Customizes the message or link text displayed after successful MFA setup.
  • MFA_RECHECK_MIN and MFA_RECHECK_MAX: Define the minimum and maximum intervals (in seconds) for random MFA rechecks.
  • MFA_QUICKLOGIN: Allows returning users to log in quickly by providing only their 2FA credentials, bypassing the primary authentication step under certain conditions.
  • MFA_ALWAYS_GO_TO_LAST_METHOD: Directs the system to always use the last successful MFA method used by the user for authentication, simplifying the login process.
  • MFA_RENAME_METHODS: A dictionary to rename MFA methods for a more user-friendly display.
  • MFA_HIDE_DISABLE: Specifies whether users can disable certain MFA methods (e.g., 'FIDO2').

Advanced MFA Settings:

  • MFA_OWNED_BY_ENTERPRISE: A flag indicating whether the security keys are owned by an enterprise, which might affect policies on key management and recovery.
  • RECOVERY_ITERATION: Sets the number of iterations for hashing recovery codes, balancing security (higher iterations) against resource usage.

Token and Application Identifiers:

  • TOKEN_ISSUER_NAME: The issuer name for TOTP tokens, typically set to the project's name to identify the token's source in authentication apps.
  • U2F_APPID and FIDO_SERVER_ID, FIDO_SERVER_NAME: Configure the application identifiers and server details for U2F and FIDO2 implementations, essential for setting up hardware-based authentication methods.

User Workflow Integration

The MFA setup and authentication processes are integrated into the user workflow, usually right after the initial login step. This might involve prompting users to set up a second factor the first time they log in after MFA is enabled:

def login(request):
    # Authenticate the user with the provided username and password.
    user = auth.authenticate(username=username, password=password)
    # If authentication is successful and a user object is returned.
    if user is not None:
        # Import the helper function to check if the user has MFA enabled.
        from mfa.helpers import has_mfa
        # Check if the user has MFA configured.
        res = has_mfa(username=username, request=request)
        # If the user has MFA enabled, `has_mfa` will return an HttpResponseRedirect object
        # that redirects the user to the MFA verification page.
        if res:
            return res
        # If the user does not have MFA or has passed the MFA check, log the user in.
        # `log_user_in` is a function that creates the user session.
        # This function should be defined in your settings or somewhere in your project
        # as `MFA_LOGIN_CALLBACK` which is called to finalize the login process.
        return log_user_in(request, username=user.username)

Let's break down the code:

User Authentication: The function starts by trying to authenticate the user using Django's auth.authenticate() method, which checks if the provided username and password are correct.

Handling MFA:

  • If the user is successfully authenticated (i.e., user is not None), the code then checks if MFA is set up for this user. This is done using the has_mfa() function from the mfa.helpers module.
  • The has_mfa() function checks the MFA status of the user and returns either False if MFA is not set up or an HttpResponseRedirect if the user needs to be redirected to the MFA verification page.

Finalizing Login:

  • If has_mfa() returns False (indicating no MFA is set up or it's already verified), the log_user_in() function is called. This function should create the user session, effectively logging the user into the application.
  • The log_user_in() function is assumed to be specified in the Django settings (or another configuration file) as MFA_LOGIN_CALLBACK, which represents a custom function you've created to handle session creation.


Ensure you have a mfa_auth_base.html template in your templates directory. This template should include blocks named 'head' and 'content' to align with the structure expected by the MFA process:

<!-- mfa_auth_base.html -->
{% extends 'base.html' %}
{% block head %}
<!-- Additional head content can go here -->
{% endblock %}
{% block content %}
<!-- MFA authentication steps will be inserted here -->
{% endblock %}

If you are using the Email Token method for MFA, provide a template named mfa_email_token_template.html. This template should format the email to include the user's name and a one-time password (OTP):

<!-- mfa_email_token_template.html -->
<p>Hello {{ user }},</p>
<p>Your one-time password (OTP) is: {{ otp }}</p>

From version 2.3.0 onwards, MFA uses a new template named mfa_base.html, which should extend your project's base.html template to maintain consistent styling across your application:

<!-- mfa_base.html -->
{% extends 'base.html' %}
{% block head %}
<!-- Custom styles for MFA pages can be added here -->
{% endblock %}
{% block content %}
<!-- Content specific to MFA will be dynamically included here -->
{% endblock %}

Include a navigation link to the MFA homepage within your application, allowing users easy access to manage their security settings:

<!-- Somewhere within your app's navigation -->
<li><a href="{% url 'mfa_home' %}">Security</a></li>

Why Use Django-MFA2?

The primary benefit of using Django-MFA2 is enhanced security. MFA is widely recommended by cybersecurity experts as it dramatically decreases the chances of successful attacks, even if passwords are stolen or leaked.

For businesses, this means protecting not only their data but also maintaining trust with their customers.

Additionally, as compliance requirements around data security tighten globally, implementing solutions like Django-MFA2 can help businesses meet regulatory obligations and avoid potential fines and legal issues.


As cyber threats become more sophisticated, the need for robust security measures like MFA in web applications becomes non-negotiable. Django-MFA2 offers a powerful, flexible, and easy-to-integrate solution that strengthens security by adding an essential layer of authentication.

For developers using Django, incorporating Django-MFA2 not only helps in safeguarding user data but also enhances the overall integrity and trustworthiness of their applications.

Whether you're building a commercial product or a personal project, considering MFA with Django-MFA2 is a step towards securing your digital assets in today's unsecured world.

Thank you for reading and I will see you on the Internet.

This post is public so feel free to share it.

If you like my free articles and would want to support my work, consider buying me a coffee:

Are you working on a project that’s encountering obstacles, or are you envisioning the next groundbreaking web application?

If Python, Django, and AI are the tools you're exploring but you need more in-depth knowledge, you're in the right place!

Get in touch for a 1-hour consultation where I can address your specific challenges.

Developer Service Blog - 1 Hour Consulting - Nuno Bispo
Are you working on a project that’s hitting roadblocks or simply dreaming up the next big web application?

Tagged in: