Thuta Learning
AdvancedSecurityintermediate

Authentication vs Authorization, Deep Dive

What you'll walk away with

  • Explain the core ideas behind Authentication vs Authorization, Deep Dive
  • Read the diagram/checklist and trace how the threat, control, and decision connect
  • Explain how this applies to your own digital life or developer workflow

Build the mental model

Authentication and authorization sound alike, but they answer two completely different questions.

Authentication answers "who are you?" — proving identity with a password, a passkey, or a valid session token.

Authorization answers a separate question: what is this identity allowed to do, right now, on this specific resource? Passing one never automatically grants the other.

Consider GET /users/123. Being logged in does not automatically entitle a user to view every user's data.

The insecure-direct-object bug

If a logged-in user can change the ID in a URL and see someone else's private data, authentication worked perfectly — but authorization failed.

Treat them as two separate gates, checked in order. Authentication confirms identity once; authorization must be re-evaluated per resource and per action.

Authentication
The process of verifying who a user is, typically by checking credentials such as a password, passkey, or valid session token.
Authorization
The process of deciding what an already-identified user is permitted to do, checked per resource and per action.
text
AUTHENTICATION VS AUTHORIZATION
-------------------------------
REQUEST
   |
   v
[AUTHENTICATION]   <- who are you?
   |
   | pass (identity confirmed)
   v
[AUTHORIZATION]    <- allowed to do THIS, on THIS resource?
   |
   +-- pass --> ALLOW (proceed)
   |
   +-- fail --> DENY (403, even though logged in)

Connect it to a real scenario

The function below models the two-gate flow as real, runnable code, checking each gate separately instead of collapsing them into one boolean.

If authentication fails, the function stops immediately and returns DENY without even looking at authorization.

Case 1 — wrong owner

User 456 requests the resource owned by user 123. Authentication passes, authorization correctly fails: DENY.

Case 2 — correct owner

The same user requests their own resource. Both gates pass: ALLOW.

Keeping the two checks structurally separate, with separate results in the output, is what catches this bug before production.

Try the working example

javascript
function checkAccess(request) {
  const authResult = request.isAuthenticated
    ? { gate: "authentication", passed: true }
    : { gate: "authentication", passed: false, reason: "not logged in" };

  if (!authResult.passed) {
    return { authentication: authResult, authorization: null, decision: "DENY" };
  }

  const isOwner = request.requestedResourceOwnerId === request.actualUserId;
  const authzResult = isOwner
    ? { gate: "authorization", passed: true }
    : {
        gate: "authorization",
        passed: false,
        reason: `user ${request.actualUserId} does not own resource owned by ${request.requestedResourceOwnerId}`,
      };

  return {
    authentication: authResult,
    authorization: authzResult,
    decision: authzResult.passed ? "ALLOW" : "DENY",
  };
}

const authenticatedButNotOwner = checkAccess({
  isAuthenticated: true,
  requestedResourceOwnerId: 123,
  actualUserId: 456,
});

const fullyAuthorized = checkAccess({
  isAuthenticated: true,
  requestedResourceOwnerId: 123,
  actualUserId: 123,
});

console.log("Case 1 - authenticated but not the owner:");
console.log(JSON.stringify(authenticatedButNotOwner, null, 2));
console.log("\nCase 2 - authenticated and owns the resource:");
console.log(JSON.stringify(fullyAuthorized, null, 2));
You should see
Case 1 - authenticated but not the owner:
{
  "authentication": {
    "gate": "authentication",
    "passed": true
  },
  "authorization": {
    "gate": "authorization",
    "passed": false,
    "reason": "user 456 does not own resource owned by 123"
  },
  "decision": "DENY"
}

Case 2 - authenticated and owns the resource:
{
  "authentication": {
    "gate": "authentication",
    "passed": true
  },
  "authorization": {
    "gate": "authorization",
    "passed": true
  },
  "decision": "ALLOW"
}

5-minute try-it

Extend checkAccess to also handle a third role, "admin", which is authorized for any resource regardless of ownership. Add a role field to the request object and update the authorization check accordingly, then verify an admin can access a resource they don't own while a regular user still cannot.

One important caution

Checking only "is this user logged in" and assuming that covers access control for every action they take.

Trusting a resource ID from the client (URL, body, query string) without verifying the authenticated user actually owns or may access it.

Check your understanding

A user successfully logs in, then changes the order ID in a URL to view another user's private order history. What should happen?

OWASP Authorization Cheat SheetDigital Privacy & Modern Security

Easy traps

  • Checking only "is this user logged in" and assuming that covers access control for every action they take.
  • Trusting a resource ID from the client (URL, body, query string) without verifying the authenticated user actually owns or may access it.
  • This is not a restart of the Cybersecurity Basics course -- it assumes passwords, 2FA, phishing, malware, encryption, and backups are already covered there. This course adds what that one doesn't: passkeys, public Wi-Fi/VPN, browser security, privacy, developer-focused auth/API security, and AI security.

Exercise

Extend checkAccess to also handle a third role, "admin", which is authorized for any resource regardless of ownership. Add a role field to the request object and update the authorization check accordingly, then verify an admin can access a resource they don't own while a regular user still cannot.

You'll know it worked when: Case 1 - authenticated but not the owner: { "authentication": { "gate": "authentication", "passed": true }, "authorization": { "gate": "authorization", "passed": false, "reason": "user 456 does not own resource owned by 123" }, "decision": "DENY" } Case 2 - authenticated and owns the resource: { "authentication": { "gate": "authentication", "passed": true }, "authorization": { "gate": "authorization", "passed": true }, "decision": "ALLOW" }

Authentication vs Authorization, Deep Dive | Thuta Learning