Security basics every engineer needs path · Identity · Topic 2 of 16

Authentication vs authorisation

Not started

**Authentication** answers "who is this?". **Authorisation** answers "is this identity allowed to do this, to this thing, right now?". They happen in that order, they fail in different ways, and many breaches come from doing the first carefully and the second not at all.

Why it matters: Mixing the two up is behind many serious breaches: an app checks that a user is logged in, but not that the record they asked for is theirs.

  1. 1Authentication proves identity

    Passwords, passkeys, one-time codes or a client certificate establish who is making the request. Failure is HTTP 401.

  2. 2Authorisation grants actions

    Given that identity, is this action on this resource allowed? Failure is HTTP 403 (or 404 if you don't want to reveal the resource exists).

  3. 3Check on every request, on the server

    Hiding a button is not authorisation. Each API call must check permissions server side, against the specific object.

  4. 4Deny by default

    If no rule allows an action, it is refused. New endpoints start closed.

1

How it works

The explanation, with examples you can run.

Authentication

Authentication turns a request into an identity: a user ID, a service account, an API client. It uses one or more factors: something you know (a password), something you have (a phone, a security key, a device holding a passkey), something you are (a fingerprint, usually just unlocking a local key). After login, a session cookie or token carries the result, so later requests don't re-authenticate from scratch.

When it fails, respond with 401 and say as little as possible. "Invalid email or password" rather than "no account with that email" avoids helping attackers enumerate accounts.

Authorisation

Authorisation takes the identity and the request and decides yes or no. Common models:

  • Role-based (RBAC): users have roles (admin, editor), roles have permissions. Simple, coarse.
  • Attribute-based (ABAC): rules over attributes of the user, the resource and the context ("managers may approve expenses under €5,000 in their own department").
  • Relationship-based (ReBAC): permissions follow relationships ("can view a document if they are a member of a folder that contains it"), as in Google's Zanzibar and systems inspired by it.

Whatever the model, the decision has to include the specific object. "Is this user an editor?" is not enough; "is this user an editor of this document?" is.

Rules that prevent most mistakes

  • Enforce on the server, for every request. The browser, the mobile app and the URL are all under the user's control.
  • Deny by default. A route without an explicit rule is refused. Many frameworks let you make this the global default.
  • Centralise the decision. One policy function or service, called from everywhere, is easier to test than ownership checks copied into every handler.
  • Don't trust identifiers from the client for ownership. Take the user ID from the authenticated session, not from a field in the request body.
  • Test it. For each endpoint, a test that a second user gets 403 or 404 on the first user's objects catches the most common bug.
⌘/Ctrl + Enter
OutputNot run yet

Press Run to see what your code prints, in order.

Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.A logged-in user changes `/api/invoices/1041` to `/api/invoices/1042` and sees another customer's invoice. What failed?
  2. 2.Which HTTP status fits a request with a valid session that lacks permission?
  3. 3.The admin page is hidden from non-admins in the React app. Is that enough?

0 of 3 right so far. Get all three to finish this topic.