Guides

Permissions that hold when someone tries the door

Hiding a menu item is not a permission. What separates access control that works from access control that looks like it works.

The Rocket ERP team

Rocket ERP3 min read

Most permission systems are tested by logging in as a restricted user and observing that the menu is shorter. That tests the menu. Whether the data is protected is a different question, and it has a different answer in more systems than you would hope.

The interface is a convenience; the server is the control

A hidden button and a blocked action are not the same thing. If the only reason a user cannot delete an invoice is that the button is not rendered, then the delete is available to anyone who can reach the endpoint directly - which, in a world of mobile apps and integrations, is a larger group than it sounds.

The rule is that every action checks its own permission on the server, independently of what the interface showed. The interface then hides what the user cannot do, as a courtesy rather than as a defence.

A useful test: ask whoever maintains the system to show you the check for a sensitive action in the code, not in the screen. If the answer is that the screen does not offer it, you have found a gap.

Three questions, not one

Access control in a business system answers three separate questions, and conflating them is where it gets muddled.

  • What may this person do? Create an invoice, approve a purchase order, run payroll.

  • Which records may they see? Their branch, their team, their own customers. This is scoping, and it is the part most often missing.

  • Which fields may they change? A salesperson may edit a quantity but not a price; a storekeeper may see a cost or may not.

A system with only the first question produces users who can do little but see everything, which is the wrong half: most real risk in a business system is in reading, not writing.

Scoping has to be the same in every direction

If a user may only see their own branch, that must hold in the list, in the search, in the report, in the export and in the lookup inside a form. A scoped list beside an unscoped picker is a particularly awkward failure: the user selects a customer they are allowed to find, and the save refuses it, so the form becomes unusable for a reason nobody can see.

The export deserves a specific mention, because it is the most common leak. A report that respects scope and an export of that report that does not is a one-click path around the whole policy.

Roles for the common case, exceptions recorded

Permissions assigned per person drift within a year: people move, someone copies a colleague settings, and nobody can say what a job title is supposed to be able to do. Roles fix that, as long as a real exception is recorded as an exception rather than quietly added to the role.

And when a permission is changed, it should take effect without the user signing out, because a permission that applies at next login is a permission that does not apply when it matters.

What to audit now

  1. List users who can post journal entries, delete documents, or change prices. Compare it to who should.

  2. Pick a restricted user and attempt a restricted action through the mobile app rather than the web interface. The apps and the API share the server checks, or they do not.

  3. Export a scoped report as a restricted user and count the rows.