Restful Authorization
title: "RESTful Authorization — Scopes, Roles, and Resource Permissions" description: "RESTful authorization controls access to resources using scopes (fine-grained) or roles (coarse-grained), enforced through middleware on each endpoint." date: 2026-06-28 lastmod: 2026-06-28 weight: 21 tags: [apis, restful] }
RESTful authorization enforces access control through OAuth 2.0 scopes for fine-grained permissions or role-based access control for user-level authorization.
What You'll Learn
- Scope-based authorization
- Role-based access control
- Resource-level permissions
Why It Matters
Authentication proves who you are. Authorization proves what you can do. Both are essential for API security.
Code Examples
# Scope-based authorization
from functools import wraps
def require_scope(scope):
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
if scope not in getattr(request, 'token_scopes', []):
return jsonify({"error": "Insufficient permissions"}), 403
return f(*args, **kwargs)
return wrapper
return decorator
SCOPES = {
'users:read': 'View user information',
'users:write': 'Create and update users',
'users:delete': 'Delete users',
'orders:read': 'View orders',
'orders:write': 'Create orders',
}
@app.route('/users')
@require_scope('users:read')
def list_users():
return jsonify([u.to_dict() for u in db.get_users()])
@app.route('/users', methods=['POST'])
@require_scope('users:write')
def create_user():
return jsonify(db.create_user(request.json)), 201
# Role-based access control
class RBAC:
ROLES = {
'admin': ['users:read', 'users:write', 'users:delete', 'orders:read', 'orders:write'],
'manager': ['users:read', 'orders:read', 'orders:write'],
'user': ['orders:read', 'orders:write'],
}
@staticmethod
def check_permission(role, permission):
return permission in RBAC.ROLES.get(role, [])
# Resource-level authorization
@app.route('/orders/<int:id>')
def get_order(id):
order = db.get_order(id)
if not order:
return jsonify({"error": "Order not found"}), 404
# Check resource ownership
user_id = getattr(request, 'user_id', None)
if order.user_id != user_id and not RBAC.check_permission(request.user_role, 'orders:read'):
return jsonify({"error": "Access denied"}), 403
return jsonify(order.to_dict())
// Scope middleware
function requireScope(scope) {
return (req, res, next) => {
if (!req.user || !req.user.scopes.includes(scope)) {
return res.status(403).json({
error: 'Insufficient permissions',
required: scope
});
}
next();
};
}
app.get('/api/users', requireScope('users:read'), (req, res) => {
res.json(db.getUsers());
});
app.post('/api/users', requireScope('users:write'), (req, res) => {
res.status(201).json(db.createUser(req.body));
});
Common Mistakes
1. Skipping Authorization After Authentication
Authentication alone doesn't grant access. Always check permissions.
2. Hard-Coded Roles
Roles and permissions should be configurable, not hard-coded.
3. No Resource Ownership Check
Users can access other users' data without ownership validation.
4. Overly Broad Scopes
A scope that grants read/write/delete to all resources is too broad.
5. Inconsistent Authorization Across Endpoints
Some endpoints check authorization, others skip it.
Practice Questions
- What is the difference between scopes and roles?
- What HTTP status code for insufficient permissions?
- What is resource-level authorization?
- How do you implement scope checking in middleware?
- What is the principle of least privilege?
Answers:
- Scopes are fine-grained permissions; roles are collections of permissions.
- 403 Forbidden.
- Checking if the authenticated user owns or has access to a specific resource.
- Extract scope from token and compare against required scope.
- Grant only the minimum permissions needed for the task.
Challenge: Implement RBAC for a REST API with admin, manager, and user roles. Add resource ownership checks for order endpoints.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro