100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

User Authentication in Django

Django's auth framework provides a User model, session-based login/logout, password hashing, and decorators to protect views — all ready to use out of the box.

Forms & AuthIntermediate10 min readJul 10, 2026
Analogies

The Built-in Authentication System

django.contrib.auth ships with a User model, a pluggable authentication backend system, and helper functions like authenticate() and login(). authenticate(request, username=..., password=...) checks credentials against the configured backends (by default, checking the database with a hashed password comparison) and returns a User object on success or None on failure, without itself starting a session — that requires a separate call to login(request, user).

🏏

Cricket analogy: authenticate() is like a stump-mic and snickometer check confirming a genuine edge happened, while login(request, user) is like the umpire actually raising the finger — confirming the fact is separate from officially acting on it.

Login, Logout, and Session State

login(request, user) attaches the user's ID to request.session, and Django's SessionMiddleware persists that session (backed by the database, cache, or signed cookies depending on SESSION_ENGINE) across subsequent requests, so request.user is automatically populated on every later request from the same browser. logout(request) clears the session data entirely, flushing the session key so the same session cookie can no longer be traced back to that user.

🏏

Cricket analogy: login() is like a player's name being added to the official team sheet for the match, staying valid for every over until logout() acts like the scorer striking that name off at the end of the innings.

Protecting Views

The @login_required decorator (from django.contrib.auth.decorators) redirects unauthenticated users to LOGIN_URL, appending a ?next= parameter so they're sent back to the original page after logging in. For class-based views, the equivalent is the LoginRequiredMixin, which must be listed first in the class's base list so its dispatch() logic runs before the view's own dispatch().

🏏

Cricket analogy: @login_required is like a stadium gate that checks your ticket before letting you to your seat, redirecting you to the box office (login page) first if you don't have one, then walking you back to your original seat.

python
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect

def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('dashboard')
        else:
            return render(request, 'login.html', {'error': 'Invalid credentials'})
    return render(request, 'login.html')

@login_required
def dashboard(request):
    return render(request, 'dashboard.html', {'user': request.user})

def logout_view(request):
    logout(request)
    return redirect('login')

Never store or compare plaintext passwords. Django's User model uses set_password() to hash passwords with PBKDF2 (or Argon2/bcrypt if configured) before storage — always use authenticate() or user.check_password(), never a manual string comparison against user.password.

LOGIN_URL in settings.py controls where @login_required redirects unauthenticated users; it defaults to '/accounts/login/' and can be pointed at a custom login view URL name.

  • authenticate() verifies credentials and returns a User or None, without starting a session.
  • login(request, user) attaches the user to the session; logout(request) clears it.
  • request.user is automatically available on every request once a session is active.
  • @login_required protects function views; LoginRequiredMixin protects class-based views.
  • Unauthenticated access attempts redirect to LOGIN_URL with a ?next= parameter.
  • Passwords are always hashed (PBKDF2 by default) — never compare them as plaintext.
  • authenticate() and login() are two distinct steps: verify, then establish session state.

Practice what you learned

Was this page helpful?

Topics covered

#Python#DjangoStudyNotes#WebDevelopment#UserAuthenticationInDjango#User#Authentication#Django#Built#Security#StudyNotes#SkillVeris