Adding Two-Factor Authentication to Django (with django-allauth)

Django Boston

October 27, 2016

Patrick Cloke

Who am I?

Two-factor (multi-factor) authentication [1] [2]

Two-factor / mutli-factor / 2FA:
Requiring a login to have multiple pieces of evidence that a user owns an account.
_images/SecureID_token_new.JPG

Requires two pieces of evidence:

  1. Knowledge (something the user knows): e.g. a password, passphrase, PIN.
  2. Possession (something the user has): e.g. RSA SecureID, mobile devices / soft token, smart cards.
  3. Inherence (something the user is): e.g. biometrics: fingerprint, retina, or voice.
[1]Multi-factor authentication on Wikipedia
[2]SecureID token new.JPG on Wikimedia Commons, released into Public Domain

Two-factor (multi-factor) authentication

Generally the second factor is a user's phone via one of two mechanisms:

_images/microsoft-authenticator.png
  • TOTP (Time-based One-Time Password Algorithm) [3], e.g. Google Authenticator, Microsoft Authenticator, Facebook Code Generator, etc. (See RFC 6238.)
  • SMS / Text message

Warning

  • Showing SMS messages on mobile phone lock screens allows easy bypassing of two-factor authentication.
  • Receiving emails (i.e. password reset emails) on a mobile phone recombines the two-factors back to a single factor.
[3]Time-based One-time Password Algorithm on Wikipedia

django-allauth [4]

_images/django-logo-negative.png

A reusable Django [5] package to work with authentication, registration, account management, and social authentication. [6]

  • Supports both local (i.e. django.contrib.auth) and "social" accounts (e.g. OpenID, OAuth, OAuth2 providers)

    • Many social providers come pre-packaged (e.g. GitHub, Amazon, Twitter)
  • Customizable (e.g. you can add custom providers, customize the "adapter")

  • Supports multiple providers in the same Django application

  • Supports multiple options for account verification (e.g. email)

[4]django-allauth on GitHub
[5]We really love Django! Check out Why Django? for some reasons why.
[6]Welcome to django-allauth: Rationale

django-allauth-2fa [7]

A reusable package that adds two-factor authentication to django-allauth. It provides the glue between django-otp [8] and django-allauth.

  • Views and middleware to modify the login workflow.
  • Views for enabling/disabling two-factor authentication.
  • Support for "backup" codes.
  • Works with Django 1.8, 1.9, 1.10, and master.
[7]django-allauth-2fa on GitHub
[8]django-otp on BitBucket

Example Workflow (1/2): User login

A user enters their username & password, like normal.

_images/login-1.png

Example Workflow (2/2): User login

  • The user is prompted for their two-factor token.
  • If successful, they are logged in as normal!
_images/login-2.png

Example Workflow (1/3): Configuring Two-Factor

  • Users are presented with a QR code for enabling two-factor authentication.
  • This supports devices which can take a picture of the QR code (e.g. Google Authenticator, Microsoft Authenticator).
_images/setup-1.png _images/microsoft-authenticator-setup.png

Example Workflow (2/3): Configuring Two-Factor

Once a user has two-factor enabled, they can:

  • Disable it
  • Create backup codes
_images/setup-2.png

Example Workflow (3/3): Configuring Two-Factor

  • Backup codes are displayed if they've been generated.
  • Each backup code can only be used once.
_images/setup-3.png

How do I set it up? (1/6)

Install the package via pip [9].

pip install django-allauth-2fa
[9]Ideally you're using a virtualenv! But virtualenv could be an entire separate lightning talk.

How do I set it up? (2/6)

  • Add django-allauth-2fa to the list of installed apps in settings.py.
  • (Also add django-allauth, django-otp, and their dependencies.)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
INSTALLED_APPS = (
    'django.contrib.sites',  # Required by allauth.
    'django.contrib.auth',  # Configure Django auth package.
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'allauth',  # Enable allauth.
    'allauth.account',
    'django_otp',  # Configure the django-otp package.
    'django_otp.plugins.otp_totp',
    'django_otp.plugins.otp_static',
    'allauth_2fa',  # Enable two-factor auth.
)

How do I set it up? (3/6)

Enable the django-allauth-2fa middleware in settings.py. [10]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
MIDDLEWARE_CLASSES = (
    # Configure Django auth package.
    'django.contrib.auth.middleware.AuthenticationMiddleware',

    # Configure the django-otp package. Note this must be after the
    # AuthenticationMiddleware.
    'django_otp.middleware.OTPMiddleware',

    # Reset login flow middleware. If this middleware is included, the login
    # flow is reset if another page is loaded between login and successfully
    # entering two-factor credentials.
    'allauth_2fa.middleware.AllauthTwoFactorMiddleware',
)
[10]django-allauth-2fa also supports the MIDDLEWARE setting from Django>=1.10 as of two days ago.

How do I set it up? (4/6)

Configure django-allauth to use the django-allauth-2fa adapter in settings.py. (This enables the two-factor authentication login workflow.)

1
2
3
4
5
6
# Set the allauth adapter to be the 2FA adapter.
ACCOUNT_ADAPTER = 'allauth_2fa.adapter.OTPAdapter'

# Configure your default site. See
# https://docs.djangoproject.com/en/dev/ref/settings/#sites.
SITE_ID = 1

How do I set it up? (5/6)

Include the django-allauth-2fa URLs/views.

1
2
3
4
5
6
7
from django.conf.urls import include, url

urlpatterns = [
    # Include the allauth and 2FA urls from their respective packages.
    url(r'^accounts/', include('allauth_2fa.urls')),
    url(r'^accounts/', include('allauth.urls')),
]

How do I set it up? (6/6)

  • You'll need to migrate your models before using django-allauth-2fa.
  • django-allauth-2fa doesn't include models or migrations, but django-allauth and django-otp do.
1
python manage.py migrate

Collaborators Wanted

Thank You!

<Thank You!>