HomeAboutExperienceProjectsArchitectureEngineeringArticlesResumeLet's Talk
Articles
June 5, 20265 min read

Authorization that scales: organizations, roles, and permissions

AuthRBACSecurity

Almost every application starts authorization the same way: an 'is_admin' flag, then a 'role' column. It works right up until a customer asks for someone who can do most of what an admin does, but not one specific thing. If roles are the unit of truth, you are now inventing a new role for every combination — and the list never stops growing.

Permissions are the unit of truth

The fix is to make permissions the primitive and roles just named bundles of them. A permission is a single capability — 'listing.publish', 'claim.approve'. A role is a convenient grouping. Checks in code always ask about a permission, never a role, so adding a new kind of user is a data change, not a code change.

Membership is explicit

In a multi-tenant system, a person is not simply 'an admin'. They are a member of an organization, with a role in that organization. The same person can be an owner in one workspace and a read-only collaborator in another. Modeling membership explicitly — user, organization, and the role between them — is what makes that possible without contortions.

  • Organization — the tenant boundary.
  • Membership — the link that says 'this user belongs to this org, with this role'.
  • Role → Permissions — the capabilities that membership grants.

Keep the check cheap

Authorization runs on every request, so it has to be fast. Carrying the necessary claims on the access token — scoped to the organization in context — avoids a database round-trip just to answer 'can this request do this?'. The token says what the user may do; the handler simply asks.

None of this is exotic, and that is the point. Boring, explicit authorization is the kind that survives real customers, audits, and the feature request that would have blown up a role-based shortcut.

Written by Elijah Soko

Get in touch