Safwanul.
← All writing

Engineering

Keep authorization rules out of route handlers

2 min read

Every authorization bug I've seen had the same shape. The rule was correct in one route handler and slightly wrong in another.

User has a direct grant, OR the user's organization owns the resource.

It's easy to say. But written inline across a dozen handlers, it drifts. Someone forgets a check, someone refactors a query, and nobody notices until an audit (or a customer) does.

One pure function

So we pulled the rule out into one pure function. It takes plain values and returns a boolean, with no database and no mocks. A thin async wrapper fetches the two facts it needs and hands them over.

The null check

One line in that function matters more than the rest: the null check. Without it, a user with no organization and a resource with no organization would match, because null === null is true. That's a cross-tenant leak hiding in a single line. Inside a handler full of await calls, you'd almost never spot it. In a pure function, it's one obvious test case.

The bigger lesson

Keep policy separate from data-fetching. The most security-critical code in the repo is now also the easiest to test, review, and trust.

Where in your codebase is a security rule still buried inside a route handler?

Originally posted on LinkedIn →