Dev.to Security 🔐 Cybersecurity 👁 0 📖 2 min read

When an invoice approval check outgrows if user.role == "admin"

Most apps start with a check like this: if user.role == "admin": approve_invoice(invoice) Then a customer asks for something more specific. Alice should be able to approve an invoice if she's a finance appro

Most apps start with a check like this:

if user.role == "admin":
    approve_invoice(invoice)

Then a customer asks for something more specific. Alice should be able to approve an invoice if she's a finance approver for Acme, the invoice belongs to Acme, the amount is under her threshold, and the environment is production. That's four conditions, and only one of them is about her role.

The usual response is more roles, or more conditionals in more handlers. One handler checks role names, another checks ownership, a background job filters by tenant. After a while the frontend and backend disagree, every access change needs a deploy, and nobody can say why a request was denied.

Some things that help:

  • Ask one question where the action happens: can(user, "approve", invoice). The handler still enforces it, and the rule itself lives in one policy.
  • Run the decision point close to the app. If every request waits on a remote auth service, you've swapped scattered ifs for added latency and an availability risk on the hot path.
  • Keep authorization data out of JWTs. Tokens grow, permissions go stale until the next refresh, and revocation gets painful.
  • Keep using your IdP for identity, and feed its user and group data into the decision. "Can Alice approve invoice 456 in Acme's production tenant?" is a question for a separate layer.
  • Migrate one area at a time, starting where it hurts most (tenant admin, billing, project membership). Fix the backend check first, then line up what the UI hides, and don't add new hardcoded branches while you move the old ones.

Decision logs help during the move. You can compare the allows and denies you expected with what really happened.

Disclosure: I work at Permit.io. This is a short take on a longer post by our CEO, Or Weis, about rebuilding authorization five times at his previous company and how a central policy store with local decision points is set up:

https://www.permit.io/blog/stop-rebuilding-permissions?utm_source=devto&utm_medium=social&utm_campaign=stop-rebuilding-permissions&utm_content=authbyexample-article

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.