Authorization
Authentication gave you a trustworthy name. Authorization decides what that name is permitted to do. The two are sequential and must never be merged: a system can know exactly who you are and still — correctly — refuse to let you delete the production database. Every “403 Forbidden” you’ve ever seen is authorization saying “I believe you’re you; you still can’t do that.”
The question authorization answers
Section titled “The question authorization answers”Reduced to its core, authorization evaluates a single predicate:
can SUBJECT perform ACTION on RESOURCE ?
"can Alice DELETE document #42 ?" → yes / noEverything else — roles, policies, permission tables — is just different machinery for computing that yes/no quickly, correctly, and maintainably. The models differ in where the rule lives and how it scales as subjects, actions, and resources multiply.
Three models, three shapes of rule
Section titled “Three models, three shapes of rule”ACLs — permissions attached to the resource
Section titled “ACLs — permissions attached to the resource”An Access Control List hangs a list of “who can do what” directly on each resource. A file says: Alice can read+write, Bob can read. This is intuitive and precise — perfect for per-object sharing (think Google Docs “share with specific people”). But it doesn’t scale to organizations: granting a new hire the same access as their team means editing thousands of ACLs by hand.
document #42 → { Alice: read,write ; Bob: read } document #43 → { Alice: read ; Carol: read,write }RBAC — permissions attached to roles
Section titled “RBAC — permissions attached to roles”Role-Based Access Control inserts a layer: users get roles, roles get permissions. You no longer grant abilities to people; you grant them to roles and assign people to roles.
Alice ─► role:editor ─► { read, write, publish } Bob ─► role:viewer ─► { read }This is the workhorse of enterprise systems because it matches how organizations actually think (“she’s an admin,” “he’s on support”). The cost is role explosion: real permissions depend on context (“editors, but only for their own region”), and encoding every combination as a separate role produces hundreds of nearly-identical roles nobody can audit.
ABAC — permissions computed from attributes
Section titled “ABAC — permissions computed from attributes”Attribute-Based Access Control decides at request time by evaluating a policy over attributes of the subject, resource, action, and environment:
ALLOW if subject.department == resource.department AND action == "read" AND environment.time is business_hoursABAC is enormously expressive — it captures rules RBAC can’t without exploding — but the cost is complexity and auditability: a policy engine is harder to reason about, and “why was this allowed?” can require replaying the whole evaluation. Many mature systems blend the two: roles for the coarse strokes, attributes for the fine print.
Least privilege, made concrete
Section titled “Least privilege, made concrete”The governing principle from the overview lands hardest here. Least privilege means every subject holds the minimum authority to do its job — and authorization is where you encode that. Two practices make it real:
- Default deny. The base case is no. Access is granted by explicit rule, never assumed. A rule you forgot to write should fail closed (deny), not fail open (allow). An “allow unless blocked” system leaks the moment someone forgets to block.
- Deny by absence, not by patching. Don’t grant broad access and then carve out exceptions; grant narrow access and add capabilities as genuinely needed. The first approach forgets an exception and leaks; the second forgets a grant and merely inconveniences someone — a far safer failure.
What does least privilege buy us, and what does it cost? It buys a small blast radius: a stolen credential or a compromised service can only reach what it was narrowly allowed. It costs ongoing maintenance — narrow grants need updating as roles change — and the occasional “I can’t access the thing I need” friction. That friction is the sound of the system working.
Enforce at the right layer
Section titled “Enforce at the right layer”A rule is only as strong as its weakest enforcement point. The cardinal error is checking authorization in the UI — hiding a “Delete” button — and calling it secure. The button is a courtesy; the attacker doesn’t use your UI, they call your API directly.
UI → hides options (UX only — NEVER a security control) API gateway → coarse checks (is this token allowed to hit this route?) service layer → the real check (can THIS subject do THIS action on THIS resource?) database → last-ditch (row-level security) — defense in depthThe authoritative check belongs at the service layer, where you know the actual subject, action, and specific resource. Gateway checks are a useful coarse filter and database row-level security is a valuable backstop, but the decision “can Alice delete document #42” can only be made where #42 and Alice are both in scope.
The thread
Section titled “The thread”Authorization is least privilege made executable. Authentication told you who crossed the trust boundary; authorization decides how far in they may go — and it must decide at the layer where the real subject and the real resource are both known, defaulting to deny when in doubt. Get this right and a compromised account is a contained incident; get it wrong and one valid login becomes the keys to everything. Next, see how identity and permission travel between systems with OAuth & JWT →.
Check your understanding
Section titled “Check your understanding”- Write the core authorization predicate (subject/action/resource) and apply it to one real example.
- Contrast ACLs, RBAC, and ABAC by where the rule lives and the main cost of each.
- Why is “default deny” safer than “default allow,” in terms of what a forgotten rule does?
- Why is hiding a button in the UI not an authorization control, and which layer is authoritative?
- Describe an IDOR vulnerability and the exact check that prevents it.