Django auth cheatsheet.
Built-in auth
INSTALLED_APPS = [..., "django.contrib.auth", "django.contrib.contenttypes"]
MIDDLEWARE = [..., "django.contrib.auth.middleware.AuthenticationMiddleware"]
AUTHENTICATION_BACKENDS = ["django.contrib.auth.backends.ModelBackend"]
Login / logout views
# urls.py
from django.contrib.auth import views as auth_views
urlpatterns = [
path("login/", auth_views.LoginView.as_view(), name="login"),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
path("password_change/", auth_views.PasswordChangeView.as_view()),
path("password_reset/", auth_views.PasswordResetView.as_view()),
]
settings
LOGIN_URL = "/login/"
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/"
Login form template
<form method="post">
{% csrf_token %}
{{ form }}
<input type="hidden" name="next" value="{{ next }}">
<button>Sign in</button>
</form>
Template path: registration/login.html.
Custom user (always do this from start)
# accounts/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
email = models.EmailField(unique=True)
bio = models.TextField(blank=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
# settings.py
AUTH_USER_MODEL = "accounts.User"
⚠️ Set this BEFORE the first migration. Switching later is painful.
Custom user manager
class UserManager(BaseUserManager):
def create_user(self, email, password, **extra):
user = self.model(email=self.normalize_email(email), **extra)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra):
extra.setdefault("is_staff", True)
extra.setdefault("is_superuser", True)
return self.create_user(email, password, **extra)
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
Check authentication
from django.contrib.auth.decorators import login_required, permission_required
@login_required
def view(request):
return ...
@permission_required("blog.add_post", raise_exception=True)
def create_post(request):
return ...
Class-based:
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
class MyView(LoginRequiredMixin, ListView):
login_url = "/login/"
class AdminView(PermissionRequiredMixin, ListView):
permission_required = "blog.delete_post"
Permissions
Built-in: <app>.<action>_<model> (e.g., blog.add_post).
Add custom:
class Post(models.Model):
...
class Meta:
permissions = [
("can_publish", "Can publish posts"),
]
Check:
request.user.has_perm("blog.can_publish")
request.user.has_perms(["blog.can_publish", "blog.delete_post"])
Groups
from django.contrib.auth.models import Group
editors = Group.objects.create(name="Editors")
editors.permissions.add(Permission.objects.get(codename="add_post"))
user.groups.add(editors)
authenticate + login
from django.contrib.auth import authenticate, login, logout
def login_view(request):
user = authenticate(request, email=email, password=password)
if user:
login(request, user)
return redirect("/")
return ...
def logout_view(request):
logout(request)
Password hashers
# settings.py
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
]
uv add argon2-cffi
Email-based password reset
Built-in PasswordResetView sends email. Configure:
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.example.com"
EMAIL_HOST_USER = "..."
EMAIL_HOST_PASSWORD = "..."
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "[email protected]"
django-allauth (OAuth + everything)
uv add django-allauth
Adds GitHub, Google, etc. Battle-tested.
Sessions
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" # fastest with Redis
SESSION_COOKIE_AGE = 60 * 60 * 24 * 30
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True # prod
SESSION_COOKIE_SAMESITE = "Lax"
CSRF
Default enabled. For AJAX, send X-CSRFToken:
fetch("/api/x/", {
method: "POST",
headers: { "X-CSRFToken": getCookie("csrftoken") },
body: ...,
});
Use @csrf_exempt sparingly.
API token auth
For DRF, see DRF cheatsheet. For Django views, use simple HTTP basic or session.
Common mistakes
- Adding custom user after first migration → painful migration.
- Forgetting
AUTH_USER_MODELsetting. - Using
Userimport instead ofget_user_model(). - Plaintext password in
User.objects.create()— usecreate_user. - Sharing session across HTTPS and HTTP — security risk.
Read this next
If you want my custom User + email-only auth setup, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .