Authorization Strategies Explained — RBAC, ABAC, ACL & OAuth Scopes
Authorization determines what an authenticated user is allowed to do — controlling access to resources, actions, and data.
What You’ll Learn
In this tutorial, you’ll learn authorization models (RBAC, ABAC, ACL, policy-based), OAuth scopes and permissions, claims-based authorization, and how to implement RBAC in Python.
Why It Matters
Authentication tells you WHO the user is. Authorization tells you WHAT they can do. Without proper authorization, any authenticated user could access admin functions, delete data, or view other users’ private information.
Real-World Use
When you view a Google Doc, authorization checks your role (viewer, commenter, editor, owner) against the document’s ACL. Doda Browser’s extension permissions system uses a form of RBAC to control which extensions can access tabs, storage, or network requests.
graph TD
subgraph "Authorization Models"
A[RBAC] --> B[Role -> Permissions]
C[ABAC] --> D[Attributes -> Policy]
E[ACL] --> F[User -> Resource Access]
G[Policy-Based] --> H[Policy Engine]
end
B --> I[Users assigned roles]
D --> J[User/Resource/Environment attributes]
F --> K[Per-resource access list]
H --> L[Externalized policy rules]
Role-Based Access Control (RBAC)
RBAC assigns permissions to roles, and users are assigned to roles. The most widely used authorization model.
class RBACSystem:
def __init__(self):
# role -> set of permissions
self.role_permissions = {}
# user_id -> set of roles
self.user_roles = {}
def add_role(self, role, permissions=None):
self.role_permissions[role] = set(permissions or [])
def assign_role(self, user_id, role):
if role not in self.role_permissions:
raise ValueError(f"Role '{role}' doesn't exist")
if user_id not in self.user_roles:
self.user_roles[user_id] = set()
self.user_roles[user_id].add(role)
def check_permission(self, user_id, permission):
roles = self.user_roles.get(user_id, set())
for role in roles:
if permission in self.role_permissions.get(role, set()):
return True
return False
def user_permissions(self, user_id):
perms = set()
for role in self.user_roles.get(user_id, set()):
perms |= self.role_permissions.get(role, set())
return perms
# Define roles and permissions
rbac = RBACSystem()
rbac.add_role("viewer", ["read:document"])
rbac.add_role("editor", ["read:document", "write:document"])
rbac.add_role("admin", ["read:document", "write:document", "delete:document", "manage:users"])
# Assign roles to users
rbac.assign_role("alice", "editor")
rbac.assign_role("bob", "viewer")
rbac.assign_role("charlie", "admin")
# Check permissions
print(f"Alice can write: {rbac.check_permission('alice', 'write:document')}")
print(f"Bob can delete: {rbac.check_permission('bob', 'delete:document')}")
print(f"Charlie's perms: {rbac.user_permissions('charlie')}")Expected output:
Alice can write: True
Bob can delete: False
Charlie's perms: {'write:document', 'manage:users', 'delete:document', 'read:document'}Attribute-Based Access Control (ABAC)
ABAC evaluates attributes of the user, resource, action, and environment against policies. More flexible than RBAC but more complex.
ABAC Policy Example
class ABACEngine:
def __init__(self):
self.policies = []
def add_policy(self, name, condition_fn, effect="allow"):
self.policies.append({"name": name, "condition": condition_fn, "effect": effect})
def authorize(self, user, resource, action, context=None):
for policy in self.policies:
if policy["condition"](user, resource, action, context or {}):
return policy["effect"] == "allow"
return False # Default deny
# Define a policy
def senior_only_edit(user, resource, action, ctx):
return action == "edit" and user.get("department") == resource.get("department")
def manager_view_salary(user, resource, action, ctx):
return action == "view_salary" and user.get("role") == "manager"
engine = ABACEngine()
engine.add_policy("senior_edit", senior_only_edit)
engine.add_policy("manager_salary", manager_view_salary)
alice = {"name": "Alice", "department": "Engineering", "role": "senior"}
bob = {"name": "Bob", "department": "Engineering", "role": "intern"}
eng_doc = {"department": "Engineering"}
print(f"Alice edit eng doc: {engine.authorize(alice, eng_doc, 'edit')}")
print(f"Bob edit eng doc: {engine.authorize(bob, eng_doc, 'edit')}")
print(f"Bob view salary: {engine.authorize(bob, eng_doc, 'view_salary')}")Expected output:
Alice edit eng doc: True
Bob edit eng doc: False
Bob view salary: FalseAccess Control Lists (ACL)
ACLs specify which users or groups have access to each resource. Each resource has a list of (subject, permission) entries.
class ACLSystem:
def __init__(self):
self.acls = {} # resource -> {user: [permissions]}
def grant(self, resource, user, permission):
if resource not in self.acls:
self.acls[resource] = {}
if user not in self.acls[resource]:
self.acls[resource][user] = []
self.acls[resource][user].append(permission)
def check(self, resource, user, permission):
return (resource in self.acls and
user in self.acls[resource] and
permission in self.acls[resource][user])
acl = ACLSystem()
acl.grant("report.pdf", "alice", "read")
acl.grant("report.pdf", "alice", "write")
acl.grant("report.pdf", "bob", "read")
print(f"Alice write report: {acl.check('report.pdf', 'alice', 'write')}")
print(f"Bob write report: {acl.check('report.pdf', 'bob', 'write')}")Expected output:
Alice write report: True
Bob write report: FalseOAuth 2.0 Scopes
OAuth 2.0 uses scopes to limit what an access token can do. Scopes are strings representing permissions.
Scope: read:email write:tasks delete:tasksThe resource server checks the token’s scopes before allowing access:
def oauth_authorize(token, required_scope):
scopes = token.get("scopes", [])
if required_scope not in scopes:
return {"error": "insufficient_scope",
"need": required_scope,
"have": scopes}
return {"allowed": True}Claims-Based Authorization
With JWT, authorization claims can be embedded directly in the token:
{
"sub": "user_42",
"role": "admin",
"department": "engineering",
"permissions": ["read:*", "write:reports", "admin:users"]
}The resource server extracts claims and enforces policies without calling an auth service.
Common Mistakes
- Confusing authentication with authorization: AuthN (who you are) ≠ AuthZ (what you can do). They must be handled separately.
- Hardcoding permissions in application code: Permissions change. Store them in a database or external policy engine.
- Role explosion: Creating roles like “manager_europe_sales” instead of combining role + attribute (ABAC).
- Default-allow instead of default-deny: Always deny by default and explicitly allow. Default-allow inevitably grants unintended access.
- Not validating scopes on every request: A token with
adminscope should only be accepted when the endpoint requires it.
Practice Questions
What’s the difference between RBAC and ABAC? RBAC grants permissions based on roles (static hierarchy). ABAC evaluates attributes (user, resource, environment) against policies (dynamic, fine-grained).
What problem does RBAC solve compared to ACLs? RBAC reduces complexity by grouping permissions into roles. ACLs need per-resource entries for each user, which doesn’t scale.
What are OAuth scopes? Strings that define the specific permissions an access token grants (e.g.,
read:email,write:calendar).Why is “default deny” important? It ensures new resources are protected by default. Explicit grants prevent accidental exposure.
How do claims in JWT support authorization? The JWT payload contains user attributes and permissions, allowing the resource server to authorize without external calls.
Challenge
Design an authorization system for a hospital: doctors, nurses, and admins. Doctors can read/write patient records. Nurses can read and add observations. Admins manage schedules. Use RBAC with at least 5 resource types and 10 permissions.
Real-World Task
Check your cloud provider’s IAM console. Identify how roles, policies, and permissions are structured. Can you find an example of ABAC-like conditions?
Mini Project: Policy Engine
Build a policy evaluation engine that supports RBAC and ABAC. Users have roles and attributes. Resources have types and attributes. Write JSON policies and test with different scenarios.
Security angle: The principle of least privilege is enforced through proper authorization — users get exactly the permissions they need. Durga Antivirus Pro uses a similar model for its admin/user/guest roles.
What’s Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
What’s Next
Congratulations on completing this Authorization tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro