django-auth

When the user wants to set up authentication, customize the User model, manage permissions, or configure authentication backends. Use when the user says "custom user model," "AbstractUser," "AbstractBaseUser," "login," "logout," "permissions," "groups," "django-allauth," "social auth," "password reset," "authentication backend," "is_authenticated," "user roles," "@login_required," or "permission_required." For DRF JWT/Token auth, see django-drf.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "django-auth" with this command: npx skills add ristemingov/django-claude-setup/ristemingov-django-claude-setup-django-auth

Django Authentication & Permissions

You are a Django authentication expert. Your goal is to help implement secure, maintainable auth systems.

Initial Assessment

Check for project context first: If .agents/django-project-context.md exists, read it for the existing User model location, auth backend, and permissions approach.

Critical first question: Does this project already have a custom User model?

  • If yes: Read it before suggesting changes.
  • If no and migrations exist: Explain that adding one now requires careful steps.
  • If new project: Always set up a custom User model before first migration.

Custom User Model (Always Do This First)

Do this before any migrate command in a new project. It's very hard to add later.

Option A: AbstractUser (Recommended — extends default User)

# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """Custom user model — add fields here as needed."""
    email = models.EmailField(unique=True)  # Make email unique if needed
    bio = models.TextField(blank=True)
    avatar = models.ImageField(upload_to='avatars/', blank=True)

    # Optional: use email as the login field
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']  # Required for createsuperuser

    def __str__(self):
        return self.email

Option B: AbstractBaseUser (Full control — more work)

Use when you need completely custom fields and don't want Django's built-in username/first_name/last_name.

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('Email is required')
        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, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

Register in Settings

# settings.py
AUTH_USER_MODEL = 'users.User'  # Always use this — never import User directly

Always Reference AUTH_USER_MODEL

# In models:
from django.conf import settings
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

# In code (when you need the actual class):
from django.contrib.auth import get_user_model
User = get_user_model()

Django's Permission System

Model-Level Permissions (Built-in)

Django auto-creates these for every model:

  • app.add_modelname
  • app.change_modelname
  • app.delete_modelname
  • app.view_modelname

Custom Permissions

class Article(models.Model):
    class Meta:
        permissions = [
            ('publish_article', 'Can publish articles'),
            ('feature_article', 'Can feature articles on homepage'),
        ]

Checking Permissions

# In views (FBV):
from django.contrib.auth.decorators import permission_required

@permission_required('articles.publish_article', raise_exception=True)
def publish_article(request, pk):
    ...

# In CBV:
from django.contrib.auth.mixins import PermissionRequiredMixin

class PublishArticleView(PermissionRequiredMixin, View):
    permission_required = 'articles.publish_article'

# In code:
if request.user.has_perm('articles.publish_article'):
    ...

# In templates:
{% if perms.articles.publish_article %}
    <button>Publish</button>
{% endif %}

Groups

from django.contrib.auth.models import Group, Permission

# Create group with permissions
editors = Group.objects.create(name='Editors')
perm = Permission.objects.get(codename='publish_article')
editors.permissions.add(perm)

# Assign user to group
user.groups.add(editors)

Authentication Backends

Default Session-Based Auth

Works out of the box. No configuration needed.

# views.py
from django.contrib.auth import authenticate, login, logout

def login_view(request):
    if request.method == 'POST':
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate(request, username=email, password=password)
        if user:
            login(request, user)
            return redirect('dashboard')
        # Handle invalid credentials

Custom Backend (e.g., email login)

# users/backends.py
from django.contrib.auth import get_user_model

class EmailBackend:
    def authenticate(self, request, username=None, password=None):
        User = get_user_model()
        try:
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        User = get_user_model()
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

# settings.py
AUTHENTICATION_BACKENDS = ['users.backends.EmailBackend']

django-allauth (Social + Email Auth)

Setup

pip install django-allauth
# settings.py
INSTALLED_APPS += [
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',  # Add providers
]

SITE_ID = 1
AUTHENTICATION_BACKENDS = ['allauth.account.auth_backends.AuthenticationBackend']

# allauth settings
ACCOUNT_LOGIN_METHODS = {'email'}          # Use email for login
ACCOUNT_SIGNUP_FIELDS = ['email*', 'password1*', 'password2*']
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'   # 'optional' or 'none'
LOGIN_REDIRECT_URL = '/dashboard/'
# urls.py
urlpatterns += [path('accounts/', include('allauth.urls'))]

Password Validation

# settings.py
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 10}},
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]

Related Skills

  • django-drf: JWT and Token authentication for REST APIs
  • django-models: Custom User model field design
  • django-admin: Register custom User in admin
  • django-views: LoginRequiredMixin and PermissionRequiredMixin

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

django-admin

No summary provided by upstream source.

Repository SourceNeeds Review
General

django-models

No summary provided by upstream source.

Repository SourceNeeds Review
General

django-views

No summary provided by upstream source.

Repository SourceNeeds Review