Two questions, answered in two places
Authentication answers who are you. The input is a proof — a password, a passkey, a token — and the output is an identity. It happens once per request, in middleware, and it knows nothing about the data the request is reaching for.
Authorisation answers what may you do. The input is an identity plus a specific object, and the output is allow or deny. It happens every time an object is touched, in the business layer or the query layer.
The most important point, and the one most often missed: middleware cannot answer the second question. [Authorize] knows Bob is Bob. It does not know what 1042 is, does not know whether 1042 is Bob's, and has nowhere to find out — that information lives in the database. This is why an endpoint can carry a perfectly good [Authorize] and still hand over someone else's data.
There is a third question sometimes conflated with authorisation: what role do you have. [Authorize(Roles = "Admin")] answers that, and it is authorisation — but only at the function level (API5, "may you call this endpoint"), not the object level (API1, "may you read this record"). Two levels, two different fixes, and a real system needs both.
| Question | Name | Where it lives | Called this when broken |
|---|---|---|---|
| Who are you? | Authentication | Middleware, once per request | A07 Authentication Failures |
| May you call this function? | Function-level authz | Attribute or policy on the action | API5 / BFLA |
| May you touch this object? | Object-level authz | Inside the query, every access | API1 / BOLA / IDOR |
Comments
Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.
You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.
Loading comments…