Authorisation
debt(d9/e5/b7/t7)
Closest to 'silent in production until users hit it' (d9). Missing authorisation checks produce no error — the endpoint returns data successfully. No detection_hints provided; SAST tools like Psalm/Phpstan generally cannot detect missing authorisation logic since they don't know which resources require ownership checks. Typically only discovered via penetration testing or breach.
Closest to 'touches multiple files / significant refactor in one component' (e5). While quick_fix shows a one-line $this->authorize() call per action, retrofitting authorisation properly means auditing every controller action, writing policies/voters, and adding tests — cross-cutting work within the controller layer.
Closest to 'strong gravitational pull' (b7). applies_to spans web and cli contexts; authorisation policies become load-bearing across the entire application — every new feature must integrate with the policy/voter system, and changes to the permission model ripple through controllers, tests, and UI.
Closest to 'serious trap' (t7). The misconception (UI hiding equals authorisation) is a catastrophic mental model error that contradicts how server-side security works. Developers from frontend backgrounds routinely assume hidden = protected, leading directly to IDOR — OWASP A01.
Also Known As
TL;DR
Explanation
Authorisation (authz) answers 'what can this user do?' — distinct from authentication ('who is this user?'). After a user authenticates, every protected action must check whether that user has permission. Authorisation models: RBAC (roles with permissions assigned to users — the most common PHP pattern); ABAC (attribute-based, evaluates resource + user + environment attributes); ACL (per-resource permission lists — flexible but hard to manage at scale). In PHP frameworks: Laravel uses Gates (closure-based checks) and Policies (model-specific classes with methods like view, create, update, delete — automatically mapped to controller actions via $this->authorize()); Symfony uses Voters (classes that implement the vote() method for granular attribute-based decisions). The most critical authorisation rule: check on every request, never rely on hiding UI elements as the only control — a hidden button is not an access control.
How It's Exploited
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Checking authorisation only in the UI layer — always enforce server-side on every request.
- Using the authenticated user's ID from user input instead of the session — always read the user ID from the session, never from POST/GET parameters.
- Missing authorisation on API endpoints when the web routes are protected — both must be checked independently.
- Not testing authorisation — write tests that verify a user cannot access another user's resources.
Avoid When
- Conflating authorisation with authentication — checking 'who is this?' instead of 'what can they do?' solves only half the security problem.
- Using authorisation checks as a substitute for input validation — a user with permission to update a record still cannot be trusted with malformed or malicious data.
- Implementing authorisation solely on the client side or UI layer — hidden buttons and disabled fields are not access controls and can be bypassed by direct API calls.
- Treating authorisation as a one-time setup rather than a per-request enforcement — permissions can change, tokens can be compromised, and every protected action must re-verify authorization.
When To Use
- A user successfully logs in to your app — you must authorise every subsequent request (view a profile, edit a post, delete a comment) before executing it, not just check if they're logged in.
- You have different user roles (admin, editor, viewer) with distinct capabilities — use RBAC to assign permissions to roles and check them before allowing actions like publishing or deleting content.
- A resource has sensitive data that some authenticated users should never access (a customer sees only their own invoices, not others') — implement resource-level authorisation checks in your business logic or ORM policies.
- Your app integrates external APIs or microservices — ensure the authenticated user token also carries authorisation claims (scopes, roles) so downstream services can independently verify permissions before responding.
Code Examples
// Missing authorisation — any user can view any order
class OrderController {
public function show(int $id): array {
return Order::findOrFail($id)->toArray();
// User 1 can access /orders/999 (belongs to user 2)
}
}
// Authorisation check before returning data
class OrderController {
public function show(Order $order): array {
// Laravel Policy — checks order->user_id === auth()->id()
$this->authorize('view', $order);
return $order->toArray();
}
}
// OrderPolicy
class OrderPolicy {
public function view(User $user, Order $order): bool {
return $user->id === $order->user_id
|| $user->hasRole('admin');
}
}