A practical SaaS authorization model separates three questions: which tenant is active, which actions the user may perform, and which resource is being accessed. A role answers the second question; it must never replace tenant isolation.
Last updated: September 8, 2026.
function canManageUsers(array $identity, int $tenantId): bool
{
return $identity['tenant_id'] === $tenantId
&& in_array('users.manage', $identity['permissions'], true);
}The server obtains tenant_id and permissions from a verified identity. A request cannot gain access by posting a different role or tenant value.
Start with permissions, then group them into roles
Use stable permission names such as projects.read, projects.write, users.manage, and billing.manage. Built-in roles can bundle them:
| Role | Typical scope |
|---|---|
| Owner | Billing, tenant settings, administrators, and all data |
| Administrator | Users, configuration, and operational data |
| Member | Daily application work |
| Read only | View and export permitted data |
Permission checks are easier to audit than scattered role-name comparisons. They also allow enterprise tenants to receive custom roles later without rewriting controllers. Deny access by default when a permission is absent or unknown.
Handle multiple memberships
A person may belong to several tenants. Store membership and role assignments against the pair of user and tenant IDs. Require an explicit active tenant for each request, and verify membership before loading tenant resources. Follow the data-access rules in tenant-isolated SQL queries.
Keep provider support separate
Internal support access should use provider roles, strong authentication, a stated reason, a short-lived elevation, and an audit record. Do not silently add support users to customer roles.
When a new customer is created, the onboarding workflow should establish its first owner atomically so the tenant is never left unmanaged.
Need role-based access for a database application?
PHPRunner includes generated authentication and permissions that can be adapted to tenant-aware applications. See PHPRunner.