Introduction
An authentication backend in Django is a class that determines how users are authenticated (logged in). By default, Django uses ModelBackend
, which authenticates users based on their username
and password
. However, Django allows developers to define custom authentication backends to modify or extend authentication behavior or authenticate users against different sources (internal or external sources). An external authentication systems like Lightweight directory Access Protocol (LDAP) server or even third-party providers.
Why Use an Authentication Backend?
Authentication backends are used when you want to:
- Authenticate users in different ways, such as logging in with an email as a username.
- Support multiple authentication methods, like social logins (Google, Facebook) or external APIs.
- Implement custom user verification logic, such as checking user roles, permissions, or account status.
How Does It Work?
Django uses authentication backends in the following way:
- When a user tries to log in, Django iterates through the backends listed in
AUTHENTICATION_BACKENDS
insettings.py
. - Each backend’s
authenticate()
method is called. If a backend returns a user, authentication is successful. - If no backend authenticates the user, login fails.
Example: Custom Email Authentication Backend
Here’s a simple authentication backend that allows users to log in with their email and password instead of a username:
# app/authentication.py
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class EmailAuthBackend:
"""Authenticate users using their email address instead of a username."""
def authenticate(self, request, username=None, password=None):
try:
user = UserModel.objects.get(email=username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
return None
def get_user(self, user_id):
"""Retrieve a user by their ID."""
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
Configuring Authentication Backends in Django
To enable a custom authentication backend, update settings.py
:
# project/settings.py
# Authentication backends configuration
AUTHENTICATION_BACKENDS = [
"path.to.EmailAuthBackend", # Allow email login
"django.contrib.auth.backends.ModelBackend", # Default username login
]
When you add a custom authentication backend like above you should consider some important changes in your application.
By default Django User model does not enforce unique email address. To ensure that the email address of each User instance is unique, it is better practice to set the email
attribute inside of your User model to unique=True
.
# accounts/models.py
class User(AbstractUser):
"""Default User model does not enforce unique emails!"""
email = models.EmailField(unique=True)
Now Django automatically enforces uniqueness at the database level, meaning:
- If someone tries to register with an existing email, the database will raise an
IntegrityError
. - However, Django’s form validation does not check this before submitting unless you explicitly add it.
Changing the email address to be unique requires additional changes. If a user registers or changes their email address within your application and the uniqueness of the email is not verified in the registration view, this will result in a 500 server error. And to have a more user friendly message instead of an error 500, you need to add additional logic to the registration form.
Add a clean_email()
method to the registration form.
# accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class RegistrationForm(UserCreationForm):
"""Register form for new User instances"""
class Meta:
model = UserModel
fields = ["username", "first_name", "email", "password1", "password2"]
def clean_email(self):
"""Ensure email is unique before saving."""
email = self.cleaned_data["email"]
if UserModel.objects.filter(email=email).exists():
raise forms.ValidationError("Email already exists. Please use a different one.")
return email
With this setup:
- Registration → Users provide a username, email, and password.
-
Login → Users can log in using either:
-
Username + Password (handled by
ModelBackend
) -
Email + Password (handled by
EmailAuthBackend
)
-
Username + Password (handled by
This gives users flexibility while still keeping the registration process structured. It’s a great balance between user convenience and maintaining Django’s built-in authentication system.
Top comments (0)