Django Authentication & Permissions

Django ships a complete authentication system in django.contrib.auth: user accounts, secure password hashing, session-based login and logout, password reset flows, and a permissions system with groups. Combined with Django's CSRF protection and secure session cookies, it gives most web applications solid authentication out of the box, with no third-party service required.

The most important decision comes on day one: use a custom user model. Changing the user model after the first migration is painful. Beyond that, the work is mostly configuration: choosing hashers, setting cookie security, adding social login or SSO if needed, and modeling permissions that match your domain.

TL;DR

Quick Example

A custom user model using email as the login identifier:

Core Concepts

The User Model

The default User has username, email, names, password, is_active, is_staff, is_superuser, groups, and permissions. A custom user model (subclassing AbstractUser, or AbstractBaseUser for full control) lets you use email login, add fields, and change behavior later without a painful migration. Always refer to the user model via settings.AUTH_USER_MODEL in ForeignKeys and get_user_model() in code. Store profile data that isn't needed for authentication in a separate one-to-one Profile model if the user table would otherwise grow large.

Sessions and Login

authenticate(request, username=..., password=...) checks credentials against the configured authentication backends. login(request, user) stores the user ID in the session and rotates the session key, preventing session fixation. The session cookie is a random ID, and session data lives server-side (database, cache, or signed cookies). AuthenticationMiddleware attaches request.user, an AnonymousUser when not logged in.

Password Hashing

Passwords are stored as algorithm$iterations$salt$hash. When you change PASSWORD_HASHERS, Django upgrades a user's hash transparently on their next login. Argon2 is the recommended algorithm, and bcrypt and scrypt are supported. See password security.

Permissions and Groups

Django's built-in permissions are model-level ("can change any order"). For object-level rules ("can change this order"), use django-guardian or django-rules, or write explicit checks in views and querysets.

Authentication Backends

AUTHENTICATION_BACKENDS lists classes that verify credentials: ModelBackend for passwords, plus backends for LDAP, remote-user headers, or social providers. Custom backends implement authenticate() and get_user().

Beyond Username and Password

See MFA and OAuth for the underlying protocols.

Best Practices

Create the Custom User Model Before the First Migration

Even class User(AbstractUser): pass gives you room to change later. Swapping user models mid-project requires hand-crafted migrations across every app referencing users.

Harden Session and Cookie Settings

In production: SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE, SECURE_HSTS_SECONDS, and SECURE_SSL_REDIRECT, with SESSION_COOKIE_SAMESITE = "Lax" (the default). Run python manage.py check --deploy to catch missing settings. See security headers.

Rate-Limit Login and Reset Endpoints

Django doesn't throttle login attempts by default. Add rate limiting (django-axes, django-ratelimit, or your reverse proxy) to slow credential stuffing and brute force.

Model Authorization Around Roles and Ownership

Use groups for roles, and restrict querysets by ownership (Order.objects.filter(customer__user=request.user)) so users can't reach others' data through any view. Test authorization for every sensitive endpoint.

Common Mistakes

Referencing auth.User Directly

Checking Permissions Only in Templates

Hiding a button with {% if perms.billing.approve_refund %} doesn't stop anyone from posting to the endpoint. Enforce permissions in views and APIs, and use templates only for presentation.

Storing Sensitive Data in Signed-Cookie Sessions

signed_cookies session storage is tamper-proof but not encrypted: clients can read its contents. Keep sensitive data in database- or cache-backed sessions.

FAQ

Should I use a custom user model?

Yes, always, for new projects. Django's documentation strongly recommends it. It costs nothing up front and avoids a difficult migration if you later need email login or extra fields.

How do I log in with email instead of username?

Use a custom user model with USERNAME_FIELD = "email", a unique email field, and a custom manager, as in the example above. django-allauth also supports email-only login with verification flows.

Does Django support two-factor authentication?

Not in core. Add it with django-allauth's MFA module (TOTP, WebAuthn, recovery codes) or django-otp. Protect admin logins especially, for example by requiring MFA for staff accounts.

Sessions or JWT for my API?

For first-party browser apps on the same site, Django sessions with CSRF protection are simpler and safer: HttpOnly cookies are inaccessible to JavaScript. Use tokens or JWT for third-party clients, mobile apps, or cross-domain APIs. See JWT.

Related Topics

References