Django by Example: User Authentication
How to manually log a user in and out. While Django provides built-in views for this, this code example shows how understanding the underlying authenticate() and login() functions is essential for custom flows.
Code
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render, redirect
from django.contrib import messages
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
# 1. Authenticate
# Checks credentials against the database
# Returns a User object if valid, None otherwise
user = authenticate(request, username=username, password=password)
if user is not None:
# 2. Login
# Creates the session and attaches user to request
login(request, user)
messages.success(request, "Welcome back!")
return redirect('home')
else:
messages.error(request, "Invalid username or password.")
return render(request, 'login.html')
def logout_view(request):
# 3. Logout
# Clears the session data
logout(request)
return redirect('login')Explanation
Django's authentication system decouples credential verification from session creation. The authenticate() function is the gateway; it accepts credentials (usually username and password) and iterates through the configured AUTHENTICATION_BACKENDS to verify them. If valid, it returns a User object; otherwise, it returns None. This design allows you to easily swap or stack backends (e.g., LDAP, OAuth, or custom logic) without changing your view code.
Once authenticated, the login() function establishes a session for the user. It creates a session record in the database and sets a cookie in the browser. Crucially, login() also rotates the session ID to prevent "session fixation" attacks, ensuring that a stolen pre-login session ID cannot be used to hijack the authenticated session.
The logout() function flushes the session data and removes the session cookie. It is best practice to redirect the user immediately after logout to prevent browser caching issues from showing sensitive data on the "back" button.
Code Breakdown
authenticate(request, ...). Always pass request as the first argument (required by some custom auth backends). This function is secure; it doesn't log anything in if it fails, it just returns None.login(request, user). This sets request.session['_auth_user_id']. After this line, request.user will be the logged-in user on all subsequent requests.logout(request). Flushes the session. It's good practice to redirect the user immediately after calling this.messages.success. A common pattern is to provide feedback after auth actions. These messages persist for one request (via the session) so they appear on the redirected page.
