I remember the first time I've used 2FA (two-factor authentication) was over 12 years ago when I worked as a sysadmin/netadmin in a Windows environment. We had to purchase this RSA appliance/server and pay separate licenses for each user in the system.
Back in those days, we also used these keyfobs with a simple screen showing the 6-digit number that automatically refreshes every x seconds. I actually thought those were really cool and when they launched a BlackBerry client I got all excited as I no longer have to carry this extra keyfob thingy.
Now that everyone has a smartphone, this type of 2FA setup is basically now free and accessible to everyone. You can easily install a 2FA client app like Google Authenticator or Twilio Authy on your phone. Many websites also now support it and will probably become more and more common as it does improve security significantly.
On the server side, there are free and open source libraries you can use to implement these TOTP (time-based one-time password) systems. So you no longer have to pay for these expensive servers and licenses. It's now completely accessible outside of the enterprise and you can implement it for free in your Django app.
In this post, I'll quickly go over how you can secure your Django admin with TOTP 2FA using the django-otp package.
Step 1: Install django-otp and qrcode
The qrcode package is actually optional here but it's good to include it to generate a QR code we can quickly scan with our phone to set up the client instead of manually typing things.
pip install django-otp qrcode
Also note that the django-otp package requires at least Python 3.7 at the time of writing.
Step 2: Update your settings.py file
Add the following in bold in INSTALLED_APPS:
INSTALLED_APPS = (
# 3rd-party apps.
Add the following in bold in MIDDLEWARE after the AuthenticationMiddleware entry:
MIDDLEWARE = (
The django_otp.plugins.otp_static is optional but I recommend including it as this will allow us to create one-time use backup codes if we get locked out via a Django management command (more on this later).
Step 3: Update your main urls.py file
Now we're ready to override the admin site settings to use the components from the django-otp package and require all superuser/staff accounts to use 2FA. If you deploy this change and you have users with current active sessions, they'll be redirected to the admin login page to re-enter their credentials and the token.
from django.contrib.sitemaps.views import sitemap
from django.urls import include, path, re_path
from django_otp.admin import OTPAdminSite
# Enforce 2FA only in production.
if not settings.DEBUG:
admin.site.__class__ = OTPAdminSite
We're basically just overriding the class here for the default admin site with the new modified admin site from django-otp. In the example above, I only want it enabled in production which is why I added the conditional check to only override if DEBUG is disabled.
That's basically it on the server side. Next time you access the Django admin, you'll be required to enter the TOTP token.
Now you're wondering, "wait a minute, I haven't set up my device yet, how do I get in?"
This is where the django_otp.plugins.otp_static app comes in. It provides you a management command addstatictoken that will generate a one-time use code to allow you to do that initial login and set up the client devices:
python manage.py addstatictoken myusername
Now that you're logged in with superuser access, you can then set up the devices:
On the next page, just select the user to link the device to and enter a device name. Leave everything else as is.
Now that you've added the device, click the qrcode link and scan the QR code with the 2FA app on your phone to complete the setup.
And you're all set! Django admin users now have an additional layer of security. :)