1

Concept

Role-Based Access Control

RBAC assigns permissions to roles, then assigns users to those roles. Instead of defining permissions separately for every individual user, the application asks which role the authenticated user has and what that role is permitted to do.

For example:

role: editor
→ permissions: [create_post, edit_own_post]

role: admin
→ permissions: [create_post, edit_any_post, delete_user]

This produces a simple permission model:

Editor
→ create posts
→ edit posts they authored

Admin
→ create posts
→ edit any post
→ delete user accounts

The advantage is simplicity. Permissions can be defined once for each role rather than repeatedly for individual users, making the system easier to build, reason about, and audit when the application has a small number of well-defined privilege tiers.

However, RBAC becomes insufficient when authorization depends on context beyond the user's role.

Consider:

Editor → can edit their own posts
Editor → cannot edit another editor's posts

Both requests come from users with exactly the same role:

role = editor

The role alone cannot determine the correct decision. The server also needs to evaluate the relationship between the user and the specific post:

Authenticated user
        ↓
Role = editor ✓
        ↓
Requested post
        ↓
Does this editor own the post?
        ↓
Allow / deny
2

Concept

Attribute-Based Access Control

ABAC makes authorization decisions by evaluating attributes of the user, the resource, the requested action, and sometimes the surrounding environment against a policy.

Instead of saying:

editor → can edit posts
admin  → can delete users

the application can express rules using multiple attributes:

allow if:
  user.department == "finance"
  AND resource.classification == "confidential"
  AND time.hour >= 9
  AND time.hour <= 17

Each attribute contributes something different to the decision:

user.department
→ Who is requesting access?

resource.classification
→ What are they trying to access?

action
→ What are they trying to do?

time.hour
→ Under what circumstances is the request happening?

The resulting decision is therefore contextual:

Request
   ↓
User attributes
   +
Resource attributes
   +
Action
   +
Environment
   ↓
Policy evaluation
   ↓
Allow / Deny

This makes ABAC capable of expressing rules that RBAC alone cannot naturally represent.

For example:

Finance employees
→ can read confidential documents
→ only during working hours
→ only within the finance organization

A role such as employee or finance_editor becomes insufficient because the decision depends on who the user is, what resource they're accessing, and the circumstances of the request.

The tradeoff is complexity. RBAC policies are often relatively easy to visualize:

admin → delete_user

An ABAC policy may involve several interacting conditions:

department
AND resource classification
AND ownership
AND action
AND time
AND organization
3

Concept

Access Control List

An ACL attaches a list of permitted users, groups, or other principals directly to a resource. Instead of asking a central role or policy engine whether access should be granted, the application looks at the resource's access-control list and determines whether the requesting identity appears with the required permission.

For example:

resource: /reports/q3.pdf

  user:alice    → read, write
  user:bob      → read
  group:finance → read

Here:

user:alice
→ explicitly has read/write access to this file

user:bob
→ has read-only access

group:finance
→ members of the finance group receive read access

The model is fundamentally resource-centric:

Requester
    ↓
Requested resource
    ↓
Resource's ACL
    ↓
Does this identity/group have the required permission?
    ↓
Allow / Deny

This makes ACLs particularly intuitive for file-and-folder systems, where different objects genuinely need different permissions.

For example:

/report.pdf
→ Alice: read/write
→ Bob: read

/payroll.xlsx
→ Alice: read
→ Finance: read/write

/public.pdf
→ Everyone: read

The major weakness is management complexity at scale. As the number of resources and users grows, ACLs can become difficult to maintain and audit.

4

Concept

Policy-Based Authorization

Policy-based authorization moves authorization logic out of individual application routes and into centralized, explicitly defined policies. The application asks a policy engine whether a particular action should be allowed before performing it.

For example:

POST /policy/evaluate
{
  "user": "bob",
  "action": "delete",
  "resource": "order:4522"
}
→ {
    "allow": false,
    "reason": "not resource owner"
  }

The request describes the authorization decision being evaluated:

user
→ Who is making the request?
action
→ What are they trying to do?
resource
→ What are they trying to act on?

The policy engine evaluates those inputs against the application's authorization rules:

Request
   ↓
Policy engine
   ↓
Evaluate rules
   ↓
Allow / Deny
   ↓
Application proceeds or rejects request

The important advantage is centralization. Instead of scattering authorization logic throughout dozens of controllers and route handlers:

if ($user->role === 'admin') {
    // ...
}

the application can delegate the decision to a shared policy layer. This creates a single place where authorization rules can be audited, tested, versioned, and changed.

Tools such as Open Policy Agent (OPA) with Rego and policy systems such as AWS IAM provide this kind of policy-driven authorization, although their architectures and policy languages differ.

The tradeoff is that centralization introduces its own complexity. Policies now need to be designed, tested, deployed, monitored, and evaluated correctly. A mistake in a centralized policy can affect many endpoints at once, so policy testing and change control become especially important.

5

Concept

Object-Level Authorization

Object-level authorization means checking whether the authenticated user is actually permitted to access the specific object requested by an endpoint. A role check alone is not enough.

For example:

GET /api/invoices/9931

The application must not simply ask:

Is the requester authenticated? ✓
Is the requester a normal user? ✓

It must also ask:

Is this user authorized to access invoice 9931?

A vulnerable handler might effectively do this:

$invoice = Invoice::findOrFail($request->id);

return $invoice;

The object ID came from the request, but nothing establishes that the authenticated user is entitled to that particular invoice.

In API security, failure to perform this check is commonly called BOLA (Broken Object Level Authorization).

Authentication proves who the requester is. Role authorization determines what class of actions they may perform. Object-level authorization determines whether they may perform that action on this specific resource.

You've completed Authorization and Access Control

Great work — explore other topics to keep learning.