django-mfa3

multi factor authentication for django
git clone https://git.ce9e.org/django-mfa3.git

NameSize
.github/dependabot.yml476B
.github/workflows/main.yml1157B
.gitignore58B
CHANGES.md4952B
LICENSE1072B
README.md4787B
mfa/__init__.py0B
mfa/admin.py767B
mfa/apps.py219B
mfa/decorators.py412B
mfa/forms.py1008B
mfa/locale/de/LC_MESSAGES/django.mo438B
mfa/locale/de/LC_MESSAGES/django.po997B
mfa/locale/fr/LC_MESSAGES/django.mo636B
mfa/locale/fr/LC_MESSAGES/django.po945B
mfa/mail.py1269B
mfa/methods/__init__.py0B
mfa/methods/fido2.py1603B
mfa/methods/recovery.py800B
mfa/methods/totp.py911B
mfa/middleware.py429B
mfa/migrations/0001_initial.py893B
mfa/migrations/0002_mfakey_last_code.py384B
mfa/migrations/0003_alter_mfakey_method.py453B
mfa/migrations/0004_alter_mfakey_id.py401B
mfa/migrations/__init__.py0B
mfa/mixins.py2021B
mfa/models.py578B
mfa/settings.py1207B
mfa/static/mfa/fido2.js1169B
mfa/static/mfa/vendor/webauthn-json.browser-ponyfill.js7113B
mfa/templates/mfa/auth_FIDO2.html569B
mfa/templates/mfa/auth_TOTP.html480B
mfa/templates/mfa/auth_recovery.html559B
mfa/templates/mfa/create_FIDO2.html474B
mfa/templates/mfa/create_TOTP.html478B
mfa/templates/mfa/create_recovery.html782B
mfa/templates/mfa/login_failed_subject.txt178B
mfa/templates/mfa/mfakey_confirm_delete.html145B
mfa/templates/mfa/mfakey_list.html1157B
mfa/templatetags/__init__.py0B
mfa/templatetags/mfa.py357B
mfa/urls.py503B
mfa/views.py4916B
pyproject.toml1391B
tests/__init__.py0B
tests/settings.py1827B
tests/templates/mfa/login_failed_email.txt423B
tests/templates/registration/login.html150B
tests/tests.py12262B
tests/urls.py618B

django-mfa3

An opinionated Django app that handles multi factor authentication (MFA) via FIDO2, TOTP, and recovery codes.

Features

Installation

pip install django-mfa3

Usage

  1. Add 'mfa' to INSTALLED_APPS
  2. Use mfa.views.LoginView instead of the regular login view. (Be sure to remove any other login routes, otherwise the multi factor authentication can be circumvented. The admin login will automatically be patched to redirect to the regular login.)
  3. Set MFA_DOMAIN = 'example.com' and MFA_SITE_TITLE = 'My site'. See settings.py for a full list of settings.
  4. Register URLs: path('mfa/', include('mfa.urls', namespace='mfa')
  5. The included templates are just examples, so you should replace them with your own
  6. FIDO2 requires client side code. You can either implement it yourself or use the included fido2.js.
  7. Somewhere in your app, add a link to 'mfa:list'

Enforce MFA

Optionally, you can add 'mfa.middleware.MFAEnforceMiddleware' to MIDDLEWARE (after AuthenticationMiddleware!). It will force users to setup two factor authentication by redirecting all authenticated requests to 'mfa:list' as long as the user has no MFAKeys. You can use mfa.decorators.public to add exceptions.

Send email on failed login attempt

If someone failes to login on the second factor that might indicate that the first factor (password) has been compromised. django-mfa3 will automatically send a warning to affected users under the following conditions:

All templates have access to the following context data: email, domain, site_name, user, method.

Status

I am not sure whether I will be able to maintain this library long-term. If you would like to help or even take ownership of this project, please contact me!

Related projects

django-mfa3 is based on pyotp and python-fido2.

It is inspired by but not otherwise affiliated with django-mfa2. A big difference between the two projects is that django-mfa2 supports many methods, while django-mfa3 only supports FIDO2 and TOTP. U2F was dropped because it is now superseded by FIDO2. Email and Trusted Devices were dropped because I felt like they have inferior security properties compared to FIDO2 and TOTP.

Another major inspiration is django-otp. It is probably the most mature library when it comes to two factor authentication in django. However, its basic structure is not compatible with FIDO2.

It is recommended to use django-mfa3 with django-axes for rate limiting. It is also compatible with django-stronghold.

Security considerations

The actual cryptography is handled by pyotp and python-fido2. This library only provides the glue code for django. Still, there could be issues in the glue.

A notable attack surface is server state: The authentication consists of three separate HTTP requests: The regular login, fetching a challenge, and a response. The server keeps some state in the session across these requests. For example, the user is temporarily stored in the session until the second factor authentication is done. The logic for handling this state is not as straight forward as I would like and there might be issues hidden in there.

Please also be careful when implementing and using this library in your project to prevent higher level security or usability issues. Please refer to other guidelines like the OWASP Cheat Sheet for more informaton on that topic.