beginner17 min

Headers and Authentication Concepts

What headers actually do, and the difference between authentication and authorization — two failures that look identical to an untrained eye.

What you'll learn

  • Explain the purpose of common request/response headers relevant to testing
  • Distinguish authentication (who you are) from authorization (what you're allowed to do)
  • Choose the correct status code (401 vs 403) for an authentication vs. authorization failure

Prerequisites

Explanation

Headers carry metadata about a request or response, separate from the actual data in the body. A tester doesn't need to memorize every possible header, but a handful come up constantly: Content-Type declares the format of the body (application/json means "parse this as JSON"); Authorization carries credentials, typically as Bearer <token>; Accept tells the server what response format the client can handle. Testing headers matters because a server that ignores a malformed Content-Type or silently accepts a request with no Authorization header at all is often a real security gap, not a cosmetic one.

The single most commonly confused pair of concepts in this space: authentication answers "who are you?" — proving identity, usually via a token, password, or API key. Authorization answers a completely different question: "given that I know who you are, are you allowed to do this specific thing?" A logged-in user is authenticated; whether that specific user can delete a specific resource is a separate, later, authorization decision.

This distinction has a direct, testable consequence: 401 Unauthorized means authentication failed — no valid credentials were presented at all (despite the confusing name, it's really about identity, not permission). 403 Forbidden means authentication succeeded but authorization failed — the server knows exactly who you are, and the answer is still no. A tester who doesn't verify which of these two the API actually returns can miss a real bug: an API that returns 401 for "user B tried to access user A's private data" is technically wrong — user B is authenticated, just not authorized for that specific resource, so the correct code is 403. Getting this wrong in real systems sometimes reveals more than intended (a 404 vs. 403 distinction can leak whether a resource exists at all to someone who shouldn't know).

Example

A simulated authorization check that correctly distinguishes 'not logged in' from 'logged in but not allowed' — no real network request is made.

function accessDecision(isAuthenticated, isAuthorizedForResource) {
  if (!isAuthenticated) return 401; // we don't know who this is
  if (!isAuthorizedForResource) return 403; // we know who it is, but no
  return 200;
}

console.log(accessDecision(false, false)); // 401
console.log(accessDecision(true, false));  // 403 -- authenticated, but not allowed
console.log(accessDecision(true, true));   // 200

Try it yourself

Try each combination and predict the status code before running.

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Guided exercise

Guided exercise

A request to view another user's private profile is made with a valid, logged-in session token, but that user isn't the profile's owner or an admin. Set expectedStatus to the correct code (401 or 403).

Checks: correctly identifies 403 as the right code

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Stuck? Get a hint.

Independent exercise

Independent exercise

Write a function classifyAuthFailure(hasValidToken, hasPermission) that returns 401 if there's no valid token at all, 403 if there's a valid token but no permission, and 200 if both are fine.

Checks: no token, no permission -> 401 · no token, would-be permission -> still 401 · valid token, no permission -> 403 · valid token and permission -> 200

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Stuck? Get a hint.

Common mistakes

  • Treating 401 and 403 as interchangeable "access denied" codes instead of testing that the API returns the specific, correct one for each situation.
  • Never testing what happens with a missing Authorization header at all, only testing with valid and clearly-invalid tokens.
  • Confusing authentication (who you are) with authorization (what you're allowed to do) when writing test case descriptions, making them harder for others to act on.

Knowledge check

Knowledge check

1. What question does authentication answer?
2. A user is logged in with a valid token but tries to access a resource they don't own and aren't permitted to see. What's the correct status code?
3. Why does the distinction between 401 and 403 matter for a tester?

Takeaway

Authentication (who you are) and authorization (what you're allowed to do) are different questions with different correct status codes — 401 for the former failing, 403 for the latter.

Summary

This lesson covered the purpose of common headers and the critical distinction between authentication and authorization, including which status code each failure should produce.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.