Bird
Raised Fist0
Expressframework~10 mins

Resource ownership checks in Express - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Resource ownership checks
Request received
Extract user ID from auth
Extract resource ID from request
Fetch resource from database
Compare resource owner ID with user ID
Allow access
Send response
The server checks if the logged-in user owns the resource before allowing access or denying it.
Execution Sample
Express
app.get('/posts/:id', async (req, res) => {
  const userId = req.user.id;
  const post = await Post.findById(req.params.id);
  if (post && post.ownerId === userId) {
    res.send(post);
  } else {
    res.status(403).send('Forbidden');
  }
});
This code checks if the logged-in user owns the post before sending it or denying access.
Execution Table
StepActionValue/User IDResource Owner IDCondition (ownerId === userId)Branch TakenResponse Sent
1Request received for post ID 101user123----
2Fetch post from DBuser123user123---
3Compare ownerId and userIduser123user123trueAllow access-
4Send post datauser123user123trueAllow accessPost data sent
5Request received for post ID 102user123----
6Fetch post from DBuser123user999---
7Compare ownerId and userIduser123user999falseDeny access-
8Send 403 Forbiddenuser123user999falseDeny access403 Forbidden sent
💡 Execution stops after sending response based on ownership check result.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 6After Step 7Final
userIdundefineduser123user123user123user123user123
post.ownerIdundefineduser123user123user999user999user999
condition ownerId === userIdundefined-true-falsefalse
responsenonenonependingnonependingsent
Key Moments - 3 Insights
Why do we compare post.ownerId with userId?
We compare to check if the logged-in user owns the resource. If they match (see execution_table step 3), access is allowed; otherwise, it is denied (step 7).
What happens if the resource is not found in the database?
If the resource is missing, the fetch returns null or undefined, so ownerId is undefined. The condition fails, and access is denied, preventing unauthorized access.
Why send a 403 status code instead of 404 when ownership check fails?
403 means 'Forbidden'—the resource exists but user can't access it. 404 means 'Not Found'. Using 403 informs the user they are unauthorized, not that the resource is missing.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the condition result at step 7?
Afalse
Bundefined
Ctrue
Dnull
💡 Hint
Check the 'Condition (ownerId === userId)' column at step 7 in the execution_table.
At which step is the 403 Forbidden response sent?
AStep 4
BStep 8
CStep 5
DStep 3
💡 Hint
Look at the 'Response Sent' column in the execution_table for the step sending '403 Forbidden sent'.
If userId and ownerId always match, what changes in the execution table?
ANo response is sent
BAll branches take 'Deny access' path
CAll branches take 'Allow access' path
DThe condition is always false
💡 Hint
Refer to the 'Branch Taken' column and condition results in the execution_table.
Concept Snapshot
Resource ownership checks in Express:
- Extract user ID from authenticated request
- Fetch resource by ID from DB
- Compare resource owner ID with user ID
- If match, allow access and send resource
- If no match, send 403 Forbidden
- Prevents unauthorized access to others' data
Full Transcript
In Express, resource ownership checks ensure users can only access their own data. When a request arrives, the server extracts the logged-in user's ID and the resource ID from the request. It fetches the resource from the database and compares the resource's owner ID with the user's ID. If they match, the server sends the resource data back. If they don't, the server responds with a 403 Forbidden status, denying access. This process protects user data by verifying ownership before allowing access.

Practice

(1/5)
1. What is the main purpose of resource ownership checks in an Express app?
easy
A. To allow any user to edit any resource
B. To ensure only the owner can access or modify their resource
C. To speed up database queries
D. To log user activity for analytics

Solution

  1. Step 1: Understand resource ownership

    Resource ownership means a resource belongs to a specific user.
  2. Step 2: Purpose of ownership checks

    Ownership checks prevent unauthorized users from accessing or changing resources they don't own.
  3. Final Answer:

    To ensure only the owner can access or modify their resource -> Option B
  4. Quick Check:

    Ownership check = restrict access to owner [OK]
Hint: Ownership checks block non-owners from resource access [OK]
Common Mistakes:
  • Thinking ownership checks speed up queries
  • Allowing all users to edit resources
  • Confusing ownership with logging
2. Which Express middleware pattern correctly checks if the logged-in user owns a resource with ID in req.params.id and owner ID in resource.ownerId?
easy
A. if (req.user.id == resource.owner) { next(); } else { res.status(401).send('Unauthorized'); }
B. if (req.user === resource.ownerId) { next(); } else { res.status(404).send('Not Found'); }
C. if (req.user.id === resource.ownerId) { next(); } else { res.status(403).send('Forbidden'); }
D. if (req.user.id !== resource.ownerId) { next(); } else { res.status(403).send('Forbidden'); }

Solution

  1. Step 1: Check user ID equality

    We compare req.user.id with resource.ownerId using strict equality to confirm ownership.
  2. Step 2: Respond with 403 if not owner

    If IDs don't match, respond with 403 Forbidden to block access.
  3. Final Answer:

    if (req.user.id === resource.ownerId) { next(); } else { res.status(403).send('Forbidden'); } -> Option C
  4. Quick Check:

    Strict equality + 403 Forbidden = correct ownership check [OK]
Hint: Use strict equality and 403 status for ownership checks [OK]
Common Mistakes:
  • Using == instead of ===
  • Sending wrong status codes like 404 or 401
  • Comparing whole user object instead of user ID
3. Given this Express route snippet, what will happen if req.user.id is '123' and resource.ownerId is '456'?
app.delete('/items/:id', (req, res) => {
  const resource = {ownerId: '456'};
  if (req.user.id === resource.ownerId) {
    res.send('Deleted');
  } else {
    res.status(403).send('Forbidden');
  }
});
medium
A. The item will be deleted and 'Deleted' sent
B. The server will crash due to undefined resource
C. Response will be 404 Not Found
D. Response will be 403 Forbidden

Solution

  1. Step 1: Compare user ID and owner ID

    Since req.user.id ('123') does not equal resource.ownerId ('456'), ownership check fails.
  2. Step 2: Return 403 Forbidden

    The else block sends a 403 Forbidden response blocking deletion.
  3. Final Answer:

    Response will be 403 Forbidden -> Option D
  4. Quick Check:

    Non-matching IDs = 403 Forbidden [OK]
Hint: Non-owner gets 403 Forbidden response [OK]
Common Mistakes:
  • Assuming deletion happens anyway
  • Confusing 403 with 404
  • Ignoring ownership check logic
4. Identify the bug in this ownership check middleware:
function checkOwnership(req, res, next) {
  const resource = {ownerId: '456'}; /* example */
  if (req.user.id = resource.ownerId) {
    next();
  } else {
    res.status(403).send('Forbidden');
  }
}
medium
A. Using assignment (=) instead of comparison (===) in the if condition
B. Missing call to next() in else block
C. Incorrect status code; should be 404 instead of 403
D. resource.ownerId is undefined

Solution

  1. Step 1: Check the if condition syntax

    The condition uses single equals (=), which assigns instead of compares, causing a bug.
  2. Step 2: Correct comparison operator

    It should use strict equality (===) to compare req.user.id and resource.ownerId.
  3. Final Answer:

    Using assignment (=) instead of comparison (===) in the if condition -> Option A
  4. Quick Check:

    Assignment in if condition = bug [OK]
Hint: Use === for comparison, not = assignment [OK]
Common Mistakes:
  • Confusing = with === in conditions
  • Thinking next() needed in else block
  • Wrong status code for forbidden access
5. You want to protect a route so only the owner of a blog post can edit it. The post's owner ID is stored in post.ownerId. Which Express middleware correctly implements this ownership check and returns 403 if the user is not the owner?
hard
A. app.put('/posts/:id', (req, res, next) => { if (req.user.id === post.ownerId) next(); else res.status(403).send('Forbidden'); }, (req, res) => { res.send('Post updated'); });
B. app.put('/posts/:id', (req, res) => { if (req.user.id !== post.ownerId) res.status(403).send('Forbidden'); else res.send('Post updated'); });
C. app.put('/posts/:id', (req, res, next) => { if (req.user.id == post.ownerId) next(); else res.status(404).send('Not Found'); }, (req, res) => { res.send('Post updated'); });
D. app.put('/posts/:id', (req, res) => { if (req.user.id === post.ownerId) res.send('Post updated'); else res.status(401).send('Unauthorized'); });

Solution

  1. Step 1: Use middleware to check ownership before update

    Middleware checks if req.user.id matches post.ownerId and calls next() if true.
  2. Step 2: Return 403 Forbidden if not owner

    If IDs don't match, respond with 403 to block unauthorized edits.
  3. Final Answer:

    app.put('/posts/:id', (req, res, next) => { if (req.user.id === post.ownerId) next(); else res.status(403).send('Forbidden'); }, (req, res) => { res.send('Post updated'); }); -> Option A
  4. Quick Check:

    Middleware + strict equality + 403 Forbidden = correct pattern [OK]
Hint: Use middleware with strict check and 403 response [OK]
Common Mistakes:
  • Using == instead of ===
  • Sending wrong status codes like 404 or 401
  • Not using middleware pattern for ownership check