Authentication foundations

Separate identity, authentication, and authorization

Distinguish an account identifier, proof of control, session state, and permission checks before building login endpoints.

Authentication answers “who is calling?”. Authorization answers “what may this caller do?”. They sound similar, and a lot of login bugs come from mixing them up. Before we write a single endpoint, I want to split the problem into four separate questions.

  1. Identity: which account is this?
  2. Authentication: what proof did the caller give us?
  3. Session: how does the server remember that proof on the next request?
  4. Authorization: may this account do this action on this resource?

Each one has a different answer, a different failure mode, and usually a different piece of code.

Our running example

Throughout this course we secure a small Books API. A user signs up, logs in, gets a session, and can manage the books they own. Nothing fancy, but every authentication problem shows up in it.

Here’s the first trap. Imagine a request to create a book:

{ "title": "The Hobbit", "ownerId": "user-42" }

That ownerId came from the client. Anyone can type any value there. The handler must ignore it, take the user ID from the validated session, and write that value itself. The session is the trusted input. The request body is not.

Login proves only one thing

A successful login answers the authentication question and nothing else. It tells you the caller controls the account. It does not tell you the user is an administrator, and it does not tell you they own book 17.

So we make the authorization decision again at every protected operation. Not once at login, but every time a handler touches a resource. In the next lessons you’ll see this as a WHERE id = ? AND owner_id = ? clause, and it’s the single most important line in the whole API.

Why the split makes failures clearer

Keeping the four questions apart also gives you better error handling.

A missing session is an authentication failure, so we answer 401. A valid session asking for someone else’s book is an authorization failure, so we answer 403 or 404. A database outage is neither. If you report it as “invalid credentials” your logs fill up with fake failed logins and you hide a real incident.

When the concepts are separate, the responses are separate too, and debugging gets a lot easier.

Try this before moving on: draw signup, login, an authenticated request, the authorization decision, and logout as five separate boxes. At every arrow between them, write down which input the server trusts and which one it doesn’t. If you can’t say where the trusted user ID comes from at each step, the design isn’t ready yet.

Lesson completed