Authorization Models

2 minute read

Authentication answers “who are you”; authorization answers “what may you do.” Models differ in how the permission decision is expressed and evaluated.

ACL — Access Control List

Per-object lists of who can do what. Together they form the access control matrix of the system.

              read  write  delete
file.txt      nitin  nitin  admin
report.pdf    team   admin  admin
  • Granularity: user-based, role-based, resource-based, group-based
  • Simple and intuitive per-resource (“who can see this doc?”)
  • Doesn’t scale for broad questions (“what can this user access across 1M resources?”) and matrix grows O(users × resources)
  • Real-world: Unix file permissions, GCP/AWS IAM bindings on resources

RBAC — Role-Based Access Control

Permissions attach to roles; users get roles.

user ──> role ──> permissions
nitin ──> "sre-oncall" ──> {read:logs, restart:service}
      └─> "viewer"     ──> {read:dashboard}
  • Easy to administer: change the role, not every user
  • Standard in enterprises and IAM (roles like roles/editor)
  • Explodes (“role explosion”) when permissions don’t map cleanly — hundreds of near-duplicate roles; can’t express context (“only my own records”, “only during business hours”)

ABAC — Attribute-Based Access Control

Decisions are computed from attributes of the subject, resource, action, and environment via policies:

allow if  user.dept == resource.dept
      and user.clearance >= resource.sensitivity
      and request.time within business_hours
  • Extremely expressive — context, time, device posture, data labels
  • Harder to audit: “who can access X” requires evaluating policies, not reading a list
  • Real-world: AWS IAM conditions, GCP IAM Conditions, XACML

ReBAC — Relationship-Based Access Control

Permissions derive from relationships in a graph: “you can edit a doc if you own it, belong to its team, or it was shared with you.”

  • Models Google Drive / Zanzibar-style sharing naturally
  • Real-world: Google Zanzibar, OpenFGA, SpiceDB
  • Right fit for social/collaborative products; overkill for simple apps

Policy Engines / Rule Engines

Decouple the decision from the app: the app asks “is this allowed?” and an engine evaluates declarative rules.

  • OPA / Rego — general-purpose policy engine (K8s admission, APIs)
  • Cedar (AWS) — readable policy language, formal analysis
  • OpenFGA / SpiceDB — ReBAC-as-a-service
App ──> "can user U do action A on resource R?" ──> Policy Engine ──> allow/deny

Benefits: consistent enforcement, auditability, testable policy-as-code, no permission logic scattered through code.

DAC vs MAC (interview trivia)

  • DAC (discretionary) — the resource owner grants access (Unix files, Google Drive sharing)
  • MAC (mandatory) — the system enforces clearance levels; owners can’t override (SELinux, military “top secret” models)

Design guidance

  • Default deny; grant explicitly
  • Least privilege — minimum permissions, minimum duration (just-in-time elevation beats standing admin)
  • Check authorization server-side on every request — never trust hidden UI buttons or unvalidated IDs (that’s IDOR/broken access control, the #1 OWASP API risk)
  • Centralize: middleware/mesh/policy engine, not per-endpoint ifs
  • Log authorization denials — they’re your best attack signal