> cs·fundamentals
interview 0% 26m read
9.4 ★ core [B][J] 1 interview Q's

Authentication & authorization

Who you are vs what you're allowed to do — the two questions every real backend must answer, and the ownership check AI forgets.

Two questions sit in front of every protected action: who are you? and are you allowed to do this? They’re different jobs — authentication and authorization — and the second one, the ownership check, is the single thing AI-generated handlers forget most often. This chapter is the builder’s model of auth, enough to specify it and catch the holes. (The interview-depth version is 2.3.)

Authentication vs authorization

Authentication answers who are you — the login step that establishes identity. Authorization answers what are you allowed to do — and it runs on every sensitive action afterward. The bouncer checks your ID at the door (authN); the rule about which rooms your ticket opens is authZ. You can absolutely be authenticated and still not authorized: logged in, but not allowed to delete a post that isn’t yours. Conflating the two is how privilege bugs are born.

A request passes through an authentication gate, then an authorization gate, then reaches the action; failing either is rejected.requestauthN: who?authZ: may you?actionfail → 401fail → 403
FIG 1 · two gates every request passes Authentication first (who are you?), then authorization (may you do THIS?). A request can clear the first and fail the second.

How login is kept: sessions vs tokens

Both answer “how does the server know it’s still you on the next request.” A session keeps the state server-side and hands the browser an opaque session ID (usually in a cookie); the server looks it up each request — easy to revoke (delete the session), but stateful. A JWT is a signed token that carries the claims (user id, expiry); the server just verifies the signature, no lookup — stateless and scalable, but you can’t easily “log someone out” before it expires. One trap worth knowing: a JWT is signed, not encrypted — its payload is readable by anyone holding it, so never put secrets in it.

The check AI forgets: ownership

Here’s the hole that ships constantly. The AI writes DELETE /api/todos/:id, checks that someone is logged in, and deletes the todo — without checking that the todo belongs to this user. Now anyone can delete anyone’s data by guessing an id. The fix is one line of authorization: confirm todo.userId === currentUser.id before acting, and return 403 if not. This — “scope every action to the logged-in user” — is the most important sentence you can add to a backend prompt.

Authenticate → authorize-ownership → act
app.delete("/api/todos/:id", async (req, res) => {
  const user = await requireAuth(req);                 // authN — 401 if missing
  const todo = await db.todo.findUnique({ where: { id: req.params.id } });
  if (!todo) return res.status(404).json({ error: "not found" });
  if (todo.userId !== user.id) {                       // authZ — the OWNERSHIP check
    return res.status(403).json({ error: "forbidden" });
  }
  await db.todo.delete({ where: { id: todo.id } });
  res.status(204).end();
});

Take out the 403 block and the endpoint “works” in every demo — and lets any logged-in user delete anyone’s todo. That missing block is exactly what to look for in AI output.

SessionJWT (token)
Stateserver-side (a session store)none — the token carries it
Revokeeasy — delete the sessionhard before expiry
Scales to many serversneeds a shared storenaturally (just verify the signature)
Reach for itclassic web appsAPIs, mobile, multiple services
Both ride in a cookie or Authorization header each request. Don't put secrets in a JWT — it's readable.

01 Learning objectives

0 / 6 done

02 Curated reading

03 Knowledge check

knowledge check3 questions · pass ≥ 70%
  1. 01easy

    Authentication vs authorization:

  2. 02medium

    Which check do AI-generated handlers most often forget?

  3. 03medium

    A JWT's payload is encrypted, so it's safe to store secrets in it.

04 Interview questions

browse all ↗

What gets asked on this topic — tap a card for how to approach it, the follow-ups, and the trap. Company tags are best-effort & sourced.

  • ★ must-know Commonly asked mid debug very common An endpoint lets any logged-in user delete a record by id, including records they don't own. What's the bug, and how do you fix it?

    The endpoint authenticates but doesn't authorize — it confirms you're logged in but not that the record is *yours*. That's a broken object-level authorization flaw (an IDOR): change the id in the URL and you act on someone else's data. The fix is an ownership check before the action — load the record, confirm record.userId === currentUser.id, and return 403 otherwise (or 404 to avoid leaking existence). It's OWASP's #1 risk and the single most common thing AI-generated handlers omit.

    What a strong answer covers
    • Authenticated ≠ authorized: logged in, but the record isn't theirs.

    • This is an IDOR / broken object-level authorization (OWASP #1).

    • Fix: ownership check before acting — 403/404 if not the owner.

    • Derive the user from the verified session/token, never the request body.

    Quick self-check

    DELETE /api/posts/:id checks the user is logged in, then deletes the post. What's missing?

    Red flag Trusting a `userId` sent in the request body to decide ownership — the client can set it to anything; derive identity server-side.

    source: OWASP Top 10 — A01: Broken Access Control ↗