Skip to main content
One idea at a time

A role belongs to a membership

Authentication answers who Maya is. Membership answers whether she belongs to Acme. Her membership role answers which Acme operations she may perform.

Taskboard uses owner, admin, and member roles. Those values belong to memberships. Maya can own Acme while being an ordinary member of Orbit.

Your frontend may hide administrative controls for a member. The API must still check the permission on every corresponding request. Hiding a button changes presentation, not authority.

Permissions describe actions​

It helps to think in terms of operations rather than a vague idea that admins can do everything. Creating tasks, inviting members, changing roles, removing members, and managing billing are different operations.

Taskboard members can create and edit tasks and add comments. Admins can additionally create projects, invite people, and delete tasks. Owners can change member roles, remove members, and manage billing. The tenancy and billing modules contain the exact checks. An Acme owner remains unauthorized to edit Orbit tasks.

The API derives the role from current database membership. Trusting a role field submitted in JSON would let a member claim to be an owner. Trusting a role loaded at login forever would let revoked privileges remain effective.

Role changes are business operations​

Removing a member affects future HTTP access and real-time access. A connected socket needs its authorization checked for delivery as well. Persistent connections must not preserve access indefinitely after a role or membership change.

Ownership also needs a policy. Removing the final owner can leave the workspace without someone able to manage billing or membership. The reference implementation protects owner membership against unsafe administrative edits rather than pretending ownership transfer is a completed feature.

A full ownership-transfer feature would need to preserve at least one owner across concurrent requests. Counting owners and then updating without coordination is insufficient. Two requests can each believe another owner remains.

The relevant checks must share the transaction and locking strategy that protects that invariant. The database schema's role enum cannot express the whole rule across multiple rows by itself.

Why recheck membership instead of trusting the role in frontend state?

Frontend state can be stale or modified. The current database membership determines whether the operation is still permitted.

Roles group permissions within one workspace. Administrative changes must preserve access rules and the workspace's ability to remain administered.

Read api/src/tenancy.ts