| name | apply-authorization-control |
| description | Use when implementing access control decisions — determining which users can perform which actions on which resources — in any API, web application, or service. |
| source | OWASP Authorization Cheat Sheet (owasp.org/www-project-cheat-sheets); OWASP API Security Top 10 2023 API1/API3/API5; NIST SP 800-162 (ABAC); CWE-285 |
| tags | ["security","owasp","authorization","rbac","abac","access-control","developer"] |
Apply Authorization Control
Enforce explicit, deny-by-default authorization at every resource access point using Role-Based (RBAC) or Attribute-Based (ABAC) access control — never relying on UI hiding or obscurity as security.
Why This Is Best Practice
Adopted by: OWASP API Security Top 10 2023 lists Broken Object Level Authorization (API1), Broken Object Property Level Authorization (API3), and Broken Function Level Authorization (API5) as the top API vulnerability classes — all caused by missing or incomplete authorization checks. NIST SP 800-162 defines ABAC as the federal standard for fine-grained access control. AWS IAM, Google Cloud IAM, and Azure RBAC all implement these patterns at cloud scale. PCI DSS v4.0 Requirement 7 mandates least-privilege access control.
Impact: OWASP reports that broken access control was the #1 web vulnerability in 2021 (A01). Broken Object Level Authorization is the top API vulnerability in 2023 — it allows any authenticated user to access any other user's data by changing an ID in the request. Dropbox's 2012 breach and Instagram's 2019 BOLA vulnerability both stemmed from missing object-level authorization. Proper authorization prevents entire classes of data exposure.
Why best: UI-level hiding (not rendering a button) and security through obscurity (unlinked URLs) are the common alternatives — they provide zero protection against direct API calls. Explicit server-side authorization checks enforced on every request are the only reliable defense.
Sources: OWASP Authorization Cheat Sheet; OWASP API Security Top 10 2023; NIST SP 800-162; CWE-285
Steps
-
Default deny: every resource access must pass an explicit authorization check:
def get_document(doc_id, current_user):
doc = db.get(doc_id)
if doc is None:
raise NotFound()
if doc.owner_id != current_user.id and not current_user.has_role('admin'):
raise Forbidden()
return doc
Never assume that authenticated = authorized. Every object-level fetch needs a check.
-
Implement Role-Based Access Control (RBAC) for function-level permissions:
ROLE_PERMISSIONS = {
'viewer': {'document:read'},
'editor': {'document:read', 'document:write'},
'admin': {'document:read', 'document:write', 'document:delete', 'user:manage'},
}
def require_permission(permission):
def decorator(func):
def wrapper(*args, **kwargs):
if permission not in ROLE_PERMISSIONS.get(current_user.role, set()):
raise Forbidden()
func(*args, **kwargs)
wrapper
decorator
():
...
Rules
- Never check authorization only in the UI — always enforce server-side on every API call.
- Object-level authorization (BOLA) check must happen after fetching the object, not before — you need the object's owner/attributes to check.
- Admin routes must still check authorization — "internal" or "admin" endpoints are primary targets.
- Indirect object references (UUIDs instead of sequential IDs) reduce guessability but are NOT authorization — still enforce ownership checks.
Common Mistakes
- Checking role but not ownership — an admin check passes for all admins, but a user should only access their own data.
- Filtering in application code after fetching all records — if the filter code has a bug, all records are exposed.
- Relying on HTTP method to infer permission — attackers change GET to POST or DELETE. Check permission explicitly per action.
- Missing authorization on bulk/batch endpoints —
PATCH /api/documents with an array body needs per-document ownership checks, not just route-level RBAC.