Permission Modeling
On this page
Permissions as Stable Contracts
Permissions should be stable identifiers like orders:read or users:delete. Stability matters because permissions become part of code, policy, and audit logs.
Action + Resource Convention
A practical naming scheme is resource:action. Keep them consistent across services.
orders:read orders:write orders:refund users:read users:ban
Enforcement Pattern
Authorization should be explicit and centralized. A common pattern is a middleware or helper that checks a principal's permissions before executing the handler.
function requirePermission(req, res, perm) {
const p = req.principal;
if (!p || !p.permissions?.includes(perm)) {
return res.status(403).json({ error: { code: 'FORBIDDEN', message: 'Insufficient permission' } });
}
}
Multi-Tenant Considerations
If you have tenants/organizations, permissions alone are not enough. Enforce tenant scoping: the user must have permission and must be operating within an allowed tenant boundary.
Production Guidance
- Log authorization denials with requestId and permission name
- Avoid checking permissions deep inside data layer (hard to audit)
- Prefer allowlists over complex policy code unless necessary