Deciding Who Can Do What
Last updated:
Hiding is not securing
Removing a button from the interface stops the average user and stops nobody who looks. Every action must be checked on the server, regardless of what the interface shows.
The most common authorisation failure we find is an endpoint that assumes the user could not have reached it, because the button was hidden.
Roles first, permissions where needed
- Start with a small number of roles reflecting real jobs
- Attach permissions to roles rather than to individuals
- Add individual overrides only where the business genuinely needs them
- Keep the number of roles small enough that people understand them
Twenty roles with overlapping permissions is unmanageable. Five clear ones covers most businesses.
Record ownership too
Role-based permissions answer “can this user edit orders?” They do not answer “can this user edit this order?” Both questions need answering.
- Filter every list query by what the user may see
- Check ownership before allowing any single-record action
- Never trust an identifier in the request to determine access
- Test with two accounts trying to reach each other's records
Make it auditable
Who did what and when, for anything consequential. That is both a security control and the answer to most “how did this happen?” questions.
Include permission changes themselves in the audit trail — who granted whom what access is frequently the important question.
Keep it operationally simple
| Requirement | Why |
|---|---|
| Someone non-technical can grant access | Otherwise it goes through a developer |
| Access can be removed instantly | Leavers |
| A list of who has what | Periodic review |
| Sensible defaults for new users | Least privilege by default |
| Temporary access with an expiry | Contractors and cover |
Frequently asked questions
How many roles should we have?
Should we use the framework's system?
How do we handle someone covering another role?
What about API access?
Everyone in your system an administrator?
That is the most common permission model and the least defensible. Worth fixing before it matters.
Related services
What we build for problems like this one