<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Zeba</title>
    <description>The latest articles on Forem by Zeba (@zeba_73ee5815b9924ff1332c).</description>
    <link>https://forem.com/zeba_73ee5815b9924ff1332c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3767107%2Fd64ae2d1-bc33-4892-b8ed-3f2f06764b26.jpg</url>
      <title>Forem: Zeba</title>
      <link>https://forem.com/zeba_73ee5815b9924ff1332c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zeba_73ee5815b9924ff1332c"/>
    <language>en</language>
    <item>
      <title>JWT Explained for Beginners — With Simple Math Analogies</title>
      <dc:creator>Zeba</dc:creator>
      <pubDate>Sun, 01 Mar 2026 21:33:47 +0000</pubDate>
      <link>https://forem.com/zeba_73ee5815b9924ff1332c/jwt-explained-for-beginners-with-simple-math-analogies-4h54</link>
      <guid>https://forem.com/zeba_73ee5815b9924ff1332c/jwt-explained-for-beginners-with-simple-math-analogies-4h54</guid>
      <description>&lt;p&gt;&lt;em&gt;When a user logs in, the server needs to remember who they are on every request. One way is sessions, but that means storing data on the server. JWT solves this differently — all the user info like user ID, roles, and expiry is packed into the token itself, so the server just verifies the signature on each request without hitting the database every time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A JWT, or JSON Web Token, is made of three parts joined by dots: Header, Payload, and Signature.&lt;br&gt;
&lt;code&gt;header.payload.signature&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Header tells us which algorithm was used to sign the token — like HS256 or RS256 — along with the token type.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Payload holds the actual user data, called "claims" — things like the user's ID, their role, when the token was issued (iat), and when it expires (exp). Common claims are: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sub → Subject (user ID)&lt;br&gt;
 iss → Issuer&lt;br&gt;
 aud → Audience&lt;br&gt;
 exp → Expiration time&lt;br&gt;
 iat → Issued at&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Signature is what keeps the token trustworthy.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To create the Signature, the server takes the Base64-encoded Header and Payload, joins them, and runs them through a hashing function along with a secret key. Think of it like: &lt;br&gt;
&lt;code&gt;Header + Payload = message&lt;br&gt;
message + key = signature.&lt;/code&gt;&lt;br&gt;
This signature is then attached to the token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When the user sends the token back,&lt;/strong&gt; the server needs to verify it. There are two ways depending on the algorithm. &lt;br&gt;
&lt;strong&gt;&lt;u&gt;1: With HS256 (symmetric)&lt;/u&gt;&lt;/strong&gt; :  During request validation, the server takes the message from the token, uses the same secret to generate a new signature, and compares it with the signature inside the token.&lt;br&gt;
Let's understand with an analogy:&lt;br&gt;
Assume:&lt;br&gt;
&lt;code&gt;secret = 3  &amp;amp;  Signing rule is :  multiplication by secret &lt;br&gt;
signature = message × secret&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;During token generation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assume &lt;/p&gt;

&lt;p&gt;&lt;code&gt;message = 10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;signature =  10 * 3 = 30&lt;br&gt;
So token ---&amp;gt;  10.30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;During Token Validation (Coming User Request (with token))&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assume coming &lt;code&gt;token ---&amp;gt;  10.30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Application will recalculate signature using the token's message:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;signaure(Coming User Request) = 10 * 3  = 30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now compare this signature with the signature attched in the token&lt;/p&gt;

&lt;p&gt;&lt;code&gt;signature(Request User's 30) == signature calculated (30)&lt;br&gt;
30 == 30 --&amp;gt; True &lt;br&gt;
✔ Token is valid.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, assume, attacker modified the message(Token)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Assume coming token ---&amp;gt; 18.30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Application will recalculate signature using the token's message:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;signaure(Request) = 18 * 3  = 36&lt;/code&gt;&lt;br&gt;
But the signature is 30, so &lt;/p&gt;

&lt;p&gt;&lt;code&gt;signature(User's 36)  != signature (30)  &lt;br&gt;
❌ Token is Invalid.  &lt;br&gt;
&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;But what if we don't want to share the same secret key everywhere? That's where RS256 comes in.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt; 2: With RS256 (asymmetric):&lt;/u&gt;&lt;/strong&gt;  The server(Application) signs using a private key, but verification is done using a public key. This is useful in microservices where multiple services need to verify tokens without ever seeing the private key.&lt;/p&gt;

&lt;p&gt;There are two keys:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Private key → used to SIGN&lt;br&gt;
Public key → used to VERIFY&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Only the Identity Provider has the private key. Your API only has the public key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔐 Signing Process (Token Generation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assume a very simple fake math model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private key operation = multiply by 3
Public key operation = divide by 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(Note: This is NOT real RSA — just to understand concept.)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assume the message generated is 10&lt;br&gt;
&lt;code&gt;message = 10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now Sign Using Private Key&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;signature = message × 3&lt;br&gt;
signature = 10 × 3 = 30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So full token conceptually: &lt;code&gt;10.30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verification Process:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Requested token: 10.30&lt;br&gt;
message = 10 &amp;amp; signature = 30&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public key = divide by 3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now it verifies:&lt;br&gt;
&lt;code&gt;expected_message = signature ÷ 3  = 30 ÷ 3 = 10&lt;br&gt;
&lt;/code&gt;Now compare:&lt;br&gt;
&lt;code&gt;expected_message == original message?&lt;br&gt;
10 == 10 → TRUE&lt;/code&gt;&lt;br&gt;
✔ Token is valid.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Let's see if the message (token) is modified"&lt;/strong&gt;&lt;br&gt;
&lt;/u&gt;&lt;br&gt;
&lt;strong&gt;Case 1: Attacker modified the message&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;Token Received: 20.30, but original token was 10.30&lt;br&gt;
so recieved message = 20 &amp;amp; signature = 30&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Verification:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;expected_message = signature ÷ 3 =&amp;gt; 30 ÷ 3 = 10&lt;/code&gt;&lt;br&gt;
Compare:&lt;br&gt;
&lt;code&gt;10 == 20 → FALSE&lt;br&gt;
❌ Token is Invalid.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2: Attacker/User Used the wrong Public Key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose used public key = divide by 5 (original was divided by 3)&lt;br&gt;
Requested token: 10.30&lt;/p&gt;

&lt;p&gt;Then:&lt;br&gt;
&lt;code&gt;expected_message = 30 ÷ 5 = 6&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Compare:&lt;br&gt;
&lt;code&gt;6 == 10 → FALSE&lt;br&gt;
❌ Invalid&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is why even if someone steals your token and changes the user ID to get admin access, it won't work. The signature will fail verification.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One important thing to remember. The payload is only Base64 encoded, not encrypted. Anyone can decode and read it. So never store sensitive data like passwords inside a JWT. The signature only proves the token wasn't tampered with; it does not hide the data.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>beginners</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Session-Based Authentication in Django (Complete Internal Flow)</title>
      <dc:creator>Zeba</dc:creator>
      <pubDate>Tue, 17 Feb 2026 19:02:04 +0000</pubDate>
      <link>https://forem.com/zeba_73ee5815b9924ff1332c/session-based-authentication-in-django-complete-internal-flow-2c8e</link>
      <guid>https://forem.com/zeba_73ee5815b9924ff1332c/session-based-authentication-in-django-complete-internal-flow-2c8e</guid>
      <description>&lt;h2&gt;
  
  
  Complete Internal Flow (From Signup to Request Lifecycle)
&lt;/h2&gt;

&lt;p&gt;Authentication is one of the most fundamental parts of any web application.&lt;br&gt;
In Django, authentication feels simple — you call authenticate() and login() and everything works.&lt;/p&gt;

&lt;p&gt;But internally, several layers coordinate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database tables&lt;/li&gt;
&lt;li&gt;Password hashing&lt;/li&gt;
&lt;li&gt;Session engine&lt;/li&gt;
&lt;li&gt;Cookies&lt;/li&gt;
&lt;li&gt;Middleware&lt;/li&gt;
&lt;li&gt;Request lifecycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding this deeply gives you architectural clarity and debugging power.&lt;br&gt;
This guide explains the complete internal flow of session-based authentication in Django — step by step.&lt;/p&gt;
&lt;h2&gt;
  
  
  Big Picture: What Django Uses by Default
&lt;/h2&gt;

&lt;p&gt;Django uses server-side session-based authentication by default via django.contrib.auth.&lt;br&gt;
That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server stores session data.&lt;/li&gt;
&lt;li&gt;The browser only stores a session ID.&lt;/li&gt;
&lt;li&gt;Every request is validated using middleware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JWT or token-based authentication is not the default — it must be added separately.&lt;/p&gt;
&lt;h2&gt;
  
  
  Core Components Involved
&lt;/h2&gt;

&lt;p&gt;Before diving into the flow, understand the building blocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 A- Database Tables&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;auth_user(table)&lt;/strong&gt;&lt;br&gt;
Stores:&lt;br&gt;
        - id (primary key)&lt;br&gt;
        - username&lt;br&gt;
        - email&lt;br&gt;
        - hashed password&lt;br&gt;
        - is_active, is_staff, etc&lt;br&gt;
    Passwords are never stored in plain text.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;django_session(table)&lt;/strong&gt;&lt;br&gt;
       Stores:&lt;br&gt;
        - session_key&lt;br&gt;
        - session_data (encoded)&lt;br&gt;
        - expire_date&lt;/p&gt;

&lt;p&gt;This table connects session keys to user IDs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 B. Browser (Client)&lt;/strong&gt;&lt;br&gt;
   The browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stores the sessionid cookie&lt;/li&gt;
&lt;li&gt;Automatically sends it with every request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important:&lt;br&gt;
  The browser never knows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The password&lt;/li&gt;
&lt;li&gt;The session data&lt;/li&gt;
&lt;li&gt;The user ID directly
It only knows a random session key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔹 C. Middleware&lt;/strong&gt;&lt;br&gt;
   Two critical middleware classes:&lt;br&gt;
    - SessionMiddleware&lt;br&gt;
    - AuthenticationMiddleware&lt;br&gt;
    These run before your view executes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s understand what happens internally when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user signs up&lt;/li&gt;
&lt;li&gt;A user logs in&lt;/li&gt;
&lt;li&gt;The browser makes future requests&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1. User Signup (Creating a User)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What Your Signup View Does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You create a user using Django’s built-in User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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"})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What Django Does Internally&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you call create_user():&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The password is automatically hashed&lt;/li&gt;
&lt;li&gt;The user is stored in the auth_user table&lt;/li&gt;
&lt;li&gt;The plain-text password is never saved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important:&lt;br&gt;
At signup time, &lt;strong&gt;no session is created&lt;/strong&gt;.&lt;br&gt;
The user is &lt;strong&gt;not logged in automatically&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Signup only creates a database record.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. User Login (Authentication Step)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Login View&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
        )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flow has two important parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authenticate() → validates credentials&lt;/li&gt;
&lt;li&gt;login() → creates the session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s break them down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.A: What authenticate() Actually Does&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;authenticate(username, password)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, Django:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Looks up the user in the auth_user table&lt;/li&gt;
&lt;li&gt;Hashes the input password&lt;/li&gt;
&lt;li&gt;Compares it with the stored hashed password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A User object if credentials are valid&lt;/li&gt;
&lt;li&gt;None if credentials are invalid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important:&lt;br&gt;
authenticate() does not create a session.&lt;br&gt;
It only verifies identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.B What login(request, user) Actually Does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where session-based authentication begins.&lt;br&gt;
When you call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;login(request, user)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Django performs three key steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create a New Session&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Django generates a random session key, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ```
 abc123xyz
 ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Store the Session in the Database&lt;/strong&gt;&lt;br&gt;
In the djnago_session table: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdur8je1ianp515uq267.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdur8je1ianp515uq267.png" alt=" " width="619" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;_auth_user_id stores the logged-in user’s ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Send Session ID to the Browser&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Django sends this header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```
Set-Cookie: sessionid=abc123xyz

```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser stores this cookie automatically. From this point &lt;br&gt;
  onward,browser includes sessionID in every request.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. What Happens on Every Request After Login
&lt;/h2&gt;

&lt;p&gt;For every future request, the browser sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Cookie: sessionid=abc123xyz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now middleware processing begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  3A. SessionMiddleware
&lt;/h2&gt;

&lt;p&gt;The first important middleware is SessionMiddleware.&lt;br&gt;
It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads sessionid from cookies&lt;/li&gt;
&lt;li&gt;Queries the django_session table&lt;/li&gt;
&lt;li&gt;Loads the session data&lt;/li&gt;
&lt;li&gt;Attaches it to request.session&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request.session["_auth_user_id"] = 5

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3B. AuthenticationMiddleware
&lt;/h2&gt;

&lt;p&gt;Next, AuthenticationMiddleware runs.&lt;/p&gt;

&lt;p&gt;It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads _auth_user_id from session&lt;/li&gt;
&lt;li&gt;Queries auth_user&lt;/li&gt;
&lt;li&gt;Fetches User object&lt;/li&gt;
&lt;li&gt;Attaches it to request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request.user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how request.user becomes available in every view.&lt;br&gt;
&lt;strong&gt;Complete Request Lifecycle Diagram&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. AnonymousUser Behavior
&lt;/h2&gt;

&lt;p&gt;Django does not automatically block unauthenticated users.&lt;/p&gt;

&lt;p&gt;Even if the user is not logged in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The view will still execute&lt;/li&gt;
&lt;li&gt;request.user will still exist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request.user.is_authenticated  # False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that case, request.user is an AnonymousUser.&lt;/p&gt;

&lt;p&gt;Middleware attaches the user to the request.&lt;br&gt;
It does not enforce access control.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Why This View Is Public
&lt;/h2&gt;

&lt;p&gt;def profile(request):&lt;br&gt;
    return JsonResponse({"profile": "data"})&lt;/p&gt;

&lt;p&gt;This view has no restriction.&lt;br&gt;
Django will not prevent unauthenticated users from accessing it.&lt;br&gt;
Security must be explicitly enforced.&lt;/p&gt;
&lt;h2&gt;
  
  
  6.How to Restrict Access Properly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Using login_required (Recommended)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib.auth.decorators import login_required

@login_required
def profile(request):
    return JsonResponse({"profile": "private data"})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If not logged in → redirect to login page&lt;/li&gt;
&lt;li&gt;If logged in → view executes normally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Manual Check&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def profile(request):
    if not request.user.is_authenticated:
        return JsonResponse(
            {"error": "Unauthorized"},
            status=401
        )

    return JsonResponse({"profile": "private data"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mental Model
&lt;/h2&gt;

&lt;p&gt;Think of the authentication flow like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🏁 Final Deep Mental Model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think in layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Layer 1 → Database (auth_user, django_session)
Layer 2 → Session Engine
Layer 3 → Middleware
Layer 4 → View
Layer 5 → Access Control Logic

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>backend</category>
      <category>django</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
