Django Authentication and User Management
Learn Django authentication system including custom user models, social authentication, permissions, and advanced user management features.
StalkTechie
Author
Django Authentication and User Management
Django provides a robust authentication system out of the box, but real-world applications often require custom user models, social authentication, and advanced permission systems. In this guide, we'll explore how to build a complete authentication system with Django.
Custom User Models
Creating a Custom User Model
Extending or replacing the default User model is recommended for any new project. Use AbstractUser to inherit from Django's base user.
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
class CustomUser(AbstractUser):
# Additional fields
phone_number = models.CharField(max_length=20, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
profile_picture = models.ImageField(
upload_to='profile_pics/%Y/%m/%d/',
null=True,
blank=True
)
bio = models.TextField(max_length=500, blank=True)
website = models.URLField(blank=True)
# Social media fields
twitter_handle = models.CharField(max_length=50, blank=True)
github_username = models.CharField(max_length=50, blank=True)
# Preferences
email_notifications = models.BooleanField(default=True)
newsletter_subscription = models.BooleanField(default=False)
# Verification and activity
email_verified = models.BooleanField(default=False)
email_verified_at = models.DateTimeField(null=True, blank=True)
last_active = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ['-date_joined']
indexes = [
models.Index(fields=['email']),
models.Index(fields=['is_active']),
models.Index(fields=['last_login']),
]
constraints = [
models.CheckConstraint(check=models.Q(date_of_birth__lt=timezone.now().date()), name='valid_dob'),
]
def __str__(self):
return self.email or self.username
@property
def full_name(self):
return f"{self.first_name} {self.last_name}".strip()
@property
def is_verified(self):
return self.email_verified
def get_display_name(self):
if self.first_name and self.last_name:
return self.full_name
return self.username
def save(self, *args, **kwargs):
# Update last_active on save if needed
super().save(*args, **kwargs)
# In settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'
Important: Set AUTH_USER_MODEL early, before first migrations. For existing projects, use AbstractBaseUser for full control (requires custom manager).
Using AbstractBaseUser for Full Customization
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
User Registration and Authentication Views
Built-in Views and Forms
Use django.contrib.auth views for login/logout.
# urls.py
from django.contrib.auth import views as auth_views
from django.urls import path
urlpatterns = [
path('login/', auth_views.LoginView.as_view(template_name='auth/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
]
Custom Registration View
Use class-based views or forms.
from django.views.generic import CreateView
from django.urls import reverse_lazy
from .forms import CustomUserCreationForm
from .models import CustomUser
class SignUpView(CreateView):
model = CustomUser
form_class = CustomUserCreationForm
template_name = 'auth/signup.html'
success_url = reverse_lazy('login')
def form_valid(self, form):
user = form.save(commit=False)
user.is_active = False # Require email verification
user.save()
# Send verification email
return super().form_valid(form)
# forms.py
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('username', 'email', 'password1', 'password2', 'phone_number')
def clean_email(self):
email = self.cleaned_data['email']
if CustomUser.objects.filter(email=email).exists():
raise forms.ValidationError("Email already in use")
return email
Email Verification
Send token-based verification emails.
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.core.mail import send_mail
def send_verification_email(user, request):
token = default_token_generator.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
verification_url = request.build_absolute_uri(f'/verify/{uid}/{token}/')
send_mail(
'Verify your email',
f'Click here: {verification_url}',
'from@example.com',
[user.email],
)
Verification view: Check token and activate user.
Password Management
- Password Reset: Use built-in views with custom templates.
- Strength: Enforce with validators in forms (e.g., min length, numbers).
- Hashing: Django uses PBKDF2 by default; configurable in settings.
# settings.py
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
]
Permissions and Groups
Django's permission system integrates with auth.
Groups and Permissions
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
# Create group
content_type = ContentType.objects.get_for_model(Product)
permission = Permission.objects.get(codename='can_publish_product')
group = Group.objects.create(name='Editors')
group.permissions.add(permission)
# Assign user
user.groups.add(group)
user.user_permissions.add(permission)
Object-Level Permissions
Use django-guardian for per-object perms.
# With django-guardian
from guardian.shortcuts import assign_perm
assign_perm('change_product', user, product_instance)
if user.has_perm('change_product', product_instance):
# Allow edit
pass
In views: Use mixins like PermissionRequiredMixin.
Custom Permissions in Models
class Product(models.Model):
# ...
class Meta:
permissions = [
('can_publish', 'Can publish product'),
('can_review', 'Can review product'),
]
Social Authentication
Use python-social-auth or django-allauth for OAuth.
Setup with django-allauth
- Install:
pip install django-allauth - Add to settings:
INSTALLED_APPS += ['allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google'] - Configure providers (e.g., Google OAuth keys).
# settings.py
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': ['profile', 'email'],
'AUTH_PARAMS': {'access_type': 'online'},
}
}
# urls.py
path('accounts/', include('allauth.urls')),
Handles signup, login, and email verification automatically.
Session and Security Management
- Settings:
SESSION_COOKIE_SECURE = True,CSRF_COOKIE_SECURE = Truein production. - Login Throttling: Use
axesfor brute-force protection. - Two-Factor Auth:
django-two-factor-auth. - Rate Limiting: On login views.
# settings.py
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'
Signals for User Events
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver
@receiver(user_logged_in)
def log_user_login(sender, user, request, **kwargs):
user.last_active = timezone.now()
user.save(update_fields=['last_active'])
# Log IP, etc.
API Authentication (REST/GraphQL)
- DRF: TokenAuthentication, JWT (djangorestframework-simplejwt).
- Session Auth: For browser APIs.
# settings.py for DRF JWT
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
Best Practices
- Always use HTTPS.
- Enforce strong passwords and email verification.
- Audit logs for logins.
- Use
django-auditlogor custom middleware. - Test auth flows with
Client.login()in tests. - Never store plain passwords; rely on Django's system.
- For large scale: Consider external auth like Auth0 or Firebase.
This covers building a secure, extensible auth system in Django. Refer to Django 5.x docs for updates.