Django Authentication and User Management

Learn Django authentication system including custom user models, social authentication, permissions, and advanced user management features.

S

StalkTechie

Author

June 27, 2025
843 views

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

  1. Install: pip install django-allauth
  2. Add to settings: INSTALLED_APPS += ['allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google']
  3. 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 = True in production.
  • Login Throttling: Use axes for 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-auditlog or 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.

Share this post:

Related Articles

Discussion

0 comments

Please log in to join the discussion.

Login to Comment