Complete Internal Flow (From Signup to Request Lifecycle)
Authentication is one of the most fundamental parts of any web application.
In Django, authentication feels simple β you call authenticate() and login() and everything works.
But internally, several layers coordinate:
- Database tables
- Password hashing
- Session engine
- Cookies
- Middleware
- Request lifecycle
Understanding this deeply gives you architectural clarity and debugging power.
This guide explains the complete internal flow of session-based authentication in Django β step by step.
Big Picture: What Django Uses by Default
Django uses server-side session-based authentication by default via django.contrib.auth.
That means:
- The server stores session data.
- The browser only stores a session ID.
- Every request is validated using middleware.
JWT or token-based authentication is not the default β it must be added separately.
Core Components Involved
Before diving into the flow, understand the building blocks.
πΉ A- Database Tables
auth_user(table)
Stores:
- id (primary key)
- username
- email
- hashed password
- is_active, is_staff, etc
Passwords are never stored in plain text.
django_session(table)
Stores:
- session_key
- session_data (encoded)
- expire_date
This table connects session keys to user IDs.
πΉ B. Browser (Client)
The browser:
- Stores the sessionid cookie
- Automatically sends it with every request
Important:
The browser never knows
- The password
- The session data
- The user ID directly It only knows a random session key.
πΉ C. Middleware
Two critical middleware classes:
- SessionMiddleware
- AuthenticationMiddleware
These run before your view executes.
Letβs understand what happens internally when:
- A user signs up
- A user logs in
- The browser makes future requests
1. User Signup (Creating a User)
What Your Signup View Does
You create a user using Djangoβs built-in User model:
from django.contrib.auth.models import User
from django.http import JsonResponse
def signup(request):
username = request.POST.get("username")
password = request.POST.get("password")
User.objects.create_user(
username=username,
password=password
)
return JsonResponse({"message": "User created successfully"})
What Django Does Internally
When you call create_user():
- The password is automatically hashed
- The user is stored in the auth_user table
- The plain-text password is never saved
Important:
At signup time, no session is created.
The user is not logged in automatically.
Signup only creates a database record.
2. User Login (Authentication Step)
Login View
from django.contrib.auth import authenticate, login
from django.http import JsonResponse
def login_view(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return JsonResponse({"message": "Login successful"})
else:
return JsonResponse(
{"error": "Invalid credentials"},
status=401
)
This flow has two important parts:
- authenticate() β validates credentials
- login() β creates the session
Letβs break them down.
2.A: What authenticate() Actually Does
authenticate(username, password)
Internally, Django:
- Looks up the user in the auth_user table
- Hashes the input password
- Compares it with the stored hashed password
It returns:
- A User object if credentials are valid
- None if credentials are invalid
Important:
authenticate() does not create a session.
It only verifies identity.
2.B What login(request, user) Actually Does
This is where session-based authentication begins.
When you call:
login(request, user)
Django performs three key steps.
Step 1: Create a New Session
Django generates a random session key, for example:
```
abc123xyz
```
Step 2: Store the Session in the Database
In the djnago_session table:
_auth_user_id stores the logged-in userβs ID.
Step 3: Send Session ID to the Browser
Django sends this header:
```
Set-Cookie: sessionid=abc123xyz
```
The browser stores this cookie automatically. From this point
onward,browser includes sessionID in every request.
3. What Happens on Every Request After Login
For every future request, the browser sends:
Cookie: sessionid=abc123xyz
Now middleware processing begins.
3A. SessionMiddleware
The first important middleware is SessionMiddleware.
It:
- Reads sessionid from cookies
- Queries the django_session table
- Loads the session data
- Attaches it to request.session
Now:
request.session["_auth_user_id"] = 5
3B. AuthenticationMiddleware
Next, AuthenticationMiddleware runs.
It:
- Reads _auth_user_id from session
- Queries auth_user
- Fetches User object
- Attaches it to request
Now:
request.user
This is how request.user becomes available in every view.
Complete Request Lifecycle Diagram
Browser Request
Cookie: sessionid=XYZ
β
SessionMiddleware
β
Load session from django_session
β
Attach request.session
β
AuthenticationMiddleware
β
Load user from auth_user
β
Attach request.user
β
Your View Executes
4. AnonymousUser Behavior
Django does not automatically block unauthenticated users.
Even if the user is not logged in:
- The view will still execute
- request.user will still exist
However:
request.user.is_authenticated # False
In that case, request.user is an AnonymousUser.
Middleware attaches the user to the request.
It does not enforce access control.
5. Why This View Is Public
def profile(request):
return JsonResponse({"profile": "data"})
This view has no restriction.
Django will not prevent unauthenticated users from accessing it.
Security must be explicitly enforced.
6.How to Restrict Access Properly
Option 1: Using login_required (Recommended)
from django.contrib.auth.decorators import login_required
@login_required
def profile(request):
return JsonResponse({"profile": "private data"})
Behavior:
- If not logged in β redirect to login page
- If logged in β view executes normally
Option 2: Manual Check
def profile(request):
if not request.user.is_authenticated:
return JsonResponse(
{"error": "Unauthorized"},
status=401
)
return JsonResponse({"profile": "private data"})
Mental Model
Think of the authentication flow like this:
Signup β Creates user (no session)
Authenticate β Validates credentials
Login β Creates session + sends cookie
SessionMiddleware β Loads session
AuthenticationMiddleware β Loads user
View execution β Always happens
Access control β Must be enforced by you
π Final Deep Mental Model
Think in layers:
Layer 1 β Database (auth_user, django_session)
Layer 2 β Session Engine
Layer 3 β Middleware
Layer 4 β View
Layer 5 β Access Control Logic

Top comments (3)
simply and briefly explained
Some comments may only be visible to logged-in visitors. Sign in to view all comments.