What are Access Control Lists (ACL)?

Last updated: July 2026

An access control list is a list attached to a resource naming which users or roles may access it and what each is allowed to do. The attachment is the idea: where role systems hang permissions on people, an ACL hangs them on the object — every record its own guest list, every entry (an access control entry) a subject paired with its rights. It is one of computing’s oldest security constructs, and in application backends it is how “only Ada and the editors can touch this document” becomes a field instead of a feature.

Key takeaways

QuestionAnswer
The structureObject → list of entries · each entry = subject + permissions
The three meaningsNetwork traffic filters · filesystem permissions · per-record app ACLs
vs. RBACACL answers “who can touch this object?” — RBAC “what can this role do?”
The scaling fixRole entries + default ACLs + class-level rules for the common case
The iron ruleEvaluated server-side, on every request — never in the client

One object’s guest list

Document "Q3 roadmap" — ACL
┌────────────────────┬───────┬───────┐
│ subject            │ read  │ write │
├────────────────────┼───────┼───────┤
│ user usr-8fk2 (Ada)│  yes  │  yes  │   ← owner
│ user usr-2mq7 (Bob)│  yes  │   —   │   ← individually granted
│ role editors       │  yes  │  yes  │   ← a role as one entry
│ public (everyone)  │   —   │   —   │   ← default: closed
└────────────────────┴───────┴───────┘

As data, on the record itself:
{ "title": "Q3 roadmap",
  "ACL": { "usr-8fk2": { "read": true, "write": true },
           "usr-2mq7": { "read": true },
           "role:editors": { "read": true, "write": true } } }

Writing that guest list in application code:

// JavaScript / Node.js — Back4app JS SDK
// A per-object ACL: this document's own guest list
const doc = new Parse.Object('Document');
doc.set('title', 'Q3 roadmap');

const acl = new Parse.ACL(currentUser);   // owner: read + write
acl.setReadAccess(reviewerId, true);      // one user: read only
acl.setRoleWriteAccess('editors', true);  // a role as an entry
acl.setPublicReadAccess(false);           // everyone else: nothing
doc.setACL(acl);

await doc.save(); // enforced server-side on every future request

The three meanings of “ACL”

Most explanations pick one silently; the term genuinely names three mechanisms:

FamilyAttached toAn entry looks likeEvaluated by
Networking ACLsRouter/firewall interfacesAllow/deny rule on IPs, ports, protocol — ordered, first match wins, implicit deny lastNetwork devices
Filesystem ACLsFiles and directoriesuser:ada:rw- — extending owner/group/other (POSIX acl(5))The operating system
Application ACLsRows, documents, objectsUser/role → read/write flags on the recordYour backend, per request

They share the shape — a list of subject-permission entries guarding a resource — and differ in everything else. This article’s home is the third meaning: the per-record permission lists of application backends, the least-covered and, for product developers, the most-used.

How a request is evaluated: the two-gate model

Layered evaluation of class-level permissions and per-object ACLsAn authenticated request first passes the class-level permission gate for the whole table or class; if allowed, the specific object's ACL is evaluated for that user and operation; only requests passing both gates reach the data.

denied

allowed

no entry

granted

Request
(user + operation)

Gate 1
class-level rules:
may this user query
Documents at all?

403

Gate 2
this object's ACL:
does an entry grant
this user this right?

Object invisible /
write refused

Data

An authenticated request first passes the class-level permission gate for the whole table or class; if allowed, the specific object's ACL is evaluated for that user and operation; only requests passing both gates reach the data.

Layering is how mature systems reconcile coarse and fine control: class-level permissions state the policy for the whole category (“only authenticated users; only moderators delete”), and the per-object ACL decides the individual record. A request must pass both gates — which means a forgotten ACL can’t open what the class rule closed, and a generous class rule still can’t expose a locked object. The same layering logic appears one level down as row-level security when the database itself enforces the row predicate.

ACL vs. RBAC vs. ABAC

ACLRBACABAC
Permissions attach toEach objectRoles assigned to usersRules over attributes
Native questionWho can touch this object?What can this role do?Is this access allowed in context?
GranularityFinest — per record, per userCoarse — per functionArbitrary — per condition
Admin costGrows with objects × subjectsGrows with rolesGrows with rule complexity
Audit “who sees X?”Trivial — read X’s listIndirect — expand rolesHard — evaluate rules
Audit “what can Ada see?”Hard — scan all objectsTrivial — read her rolesHard
WeaknessSprawlRole explosion, no per-object nuanceOpaque policy debugging

The honest answer is composition, not competition: roles handle access that follows job function; ACLs handle the per-object decisions roles can’t express (“this draft, these two reviewers”); attribute rules step in when context matters (time, tenant, state). The practical hinge between the first two is the role-entry ACE — an ACL line whose subject is a role — which keeps object-level control while delegating membership churn to the role system.

The scaling problem — and the mitigation ladder

Naive per-object ACLs grow as N objects × M subjects: a million documents each listing individual users means every hire, departure, and reorganization edits lists scattered across the dataset — the “hard to manage” every textbook mentions, made concrete. The mitigation ladder, in the order to climb it: role entries (one ACE covers a changing population; membership updates in one place); default ACLs (each new object born with owner-read/write and the right role entries — the application analog of POSIX default ACLs on directories); class-level rules for the common case, reserving per-object lists for exceptions; and, at relationship-heavy scale, graph-based authorization (ReBAC) that derives access from relationships instead of storing lists at all. Systems that skip the ladder don’t abandon ACLs — they drown in them.

Enforcement: server-side or not at all

An ACL enforced in the client is a suggestion. Hiding buttons, filtering lists in JavaScript, or trusting the app to send only permitted IDs all fail the same way: the attacker edits the request, not the UI — increment /documents/41 to /documents/42 and read someone else’s record. That failure class — broken object-level authorization, the top entry in OWASP’s API security list — is precisely what per-object ACLs exist to close, and the OWASP guidance is blunt: authorization checks run server-side, per request, per object; possessing access to a type of object never implies access to every object of that type. The evaluation belongs in the data layer, where no client path can route around it.

Common use cases

  • User-generated content — each post, file, or note owned by its creator, shared record by record.
  • Document collaboration — per-document viewer/editor lists; the share dialog is an ACL editor wearing UX.
  • Multi-user records with exceptions — the HR case: the record’s subject reads it, their manager writes it, the auditors role reads everything.
  • Tenant and team scoping — role entries per team on shared classes, with per-object grants for cross-team exceptions.
  • Private-by-default apps — messaging, health, finance: every object closed at creation, opened only by explicit entries.

Should you use ACLs or roles? A decision matrix

SituationReach for
Access follows job function across many recordsRoles (RBAC)
Each record needs its own sharing decisionsACLs
Both patterns at once (most real apps)Class rules + role-entry ACLs
”Everyone can read, owner can write”ACL public-read flag + owner entry
Rules depend on context (time, state, tenant)Attribute conditions above the ACL
Deep relationship logic (org charts, nested groups)ReBAC-style systems

Limitations and trade-offs

  • Sprawl is the default trajectory. Without role entries and defaults, per-object lists become unauditable confetti; the mitigation ladder is not optional at scale.
  • “What can this user access?” is the expensive query. ACLs optimize the per-object audit; the per-subject inventory requires scanning or secondary indexes.
  • Wrong defaults are silent breaches. An object created public-readable stays public until noticed; default ACLs deserve the same review as code.
  • Performance rides the check. Every read filters by ACL; the evaluation must be indexed and enforced in the data layer, not bolted on per endpoint.
  • ACLs authorize; they don’t authenticate. The list is only as good as the identity presented to it — sessions and tokens are the upstream dependency.

ACLs on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. ACLs here are a first-class field: every object carries one, the code tabs above are the complete API — owner defaults, per-user grants, role entries, public flags — and enforcement happens in Back4app on every REST, GraphQL, and Live Query request, so real-time subscriptions respect the same guest lists as queries. The two-gate model ships intact: class-level permissions set the category policy in the dashboard, per-object ACLs refine it record by record, and a default-ACL setting makes new objects private-by-owner from birth. The scaling ladder is built in — roles are objects you manage like any other data — leaving the design decisions, not the enforcement machinery, as your share of the work.

Frequently asked questions

What is an ACL in simple terms?

A guest list attached to each resource: it names who may access that specific object and what each of them may do — Ada can read and write, Bob can only read, everyone else stays out. The list travels with the object, so every object can have different rules.

What is an example of an ACL?

A document record whose ACL reads: owner — read and write; the reviewers role — read; public — no access. In a database that is literally a field on the row or document; in a filesystem it is metadata on the file; on a router it is an ordered list of allow/deny traffic rules.

What is an access control entry (ACE)?

One line of the list: a subject (a user, role, or "everyone") paired with the permissions granted or denied to it. An ACL is simply an ordered collection of ACEs attached to one resource.

What are the types of ACLs?

Three families share the name: networking ACLs (ordered traffic filters on routers and firewalls), filesystem ACLs (per-file permission lists extending owner/group/other), and application or database ACLs (per-record permission lists in your data layer). In backend development, the third is usually the one meant.

What is the difference between ACL and RBAC?

Direction of attachment. An ACL hangs permissions on each resource, per subject — ideal when individual objects need individual decisions. RBAC hangs permissions on roles and assigns users to them — ideal when access follows job function across many resources. Real systems combine them: roles for the broad strokes, ACLs for per-object exceptions.

How do ACLs work in a database?

Each row or document carries (or references) its own permission list — typically an ACL field mapping user IDs and role names to read/write flags. The database or backend evaluates it on every operation, which pairs naturally with row-level security and per-table permission layers.

What is the difference between an ACL and a capability list?

Two views of the same access matrix: an ACL is a column — stored with the object, listing its subjects — while a capability list is a row — stored with the subject, listing its objects. ACLs make "who can touch this object?" instantly auditable; capabilities make "what can this user touch?" easy but revocation harder.

Why don't ACLs scale on their own?

Because the bookkeeping grows as objects × subjects: every hire, departure, and team change means editing lists scattered across millions of objects. The mitigations are role entries (one ACE covers a changing group), default ACLs applied at creation, and class-level rules handling the common case so per-object lists handle only exceptions.

What is the difference between per-object and per-class permissions?

Granularity. Per-class (or per-table) permissions gate a whole category — "only logged-in users may query Documents." Per-object ACLs gate one record — "only Ada may read this document." Layered systems check the class gate first, then the object's ACL; a request must pass both.

Related terms

Compare with

Further reading

Ready to build your backend?

Start your project on Back4app in minutes — database, auth, APIs, and Cloud Code included. No credit card required.

Written and reviewed by Back4app Engineering, Back4app Engineering · Published 2026-07-24