Roles and permissions

By default, Launchway comes with a flexible roles and permissions system. One role is assigned many permissions and each user within an organization must be assigned one of these roles. Users have a different role assignment per organization, allowing them to be, for example, an admin in one organization and a regular non-admin in another.

Roles and permissions are totally optional. Validating a users access to a certain feature or endpoint is a separate process to actually fetching data or performing mutations. It is entirely up to you where or how often you wish to validate a users access, if at all. It is set up by default because if you start without and then decided to retrofit it to your database schema down the line, it will be considerably more hassle.

Permissions

Permissions are modeled on the role-based access control (RBAC) model. You may be familiar with this system from apps like Stripe, GitHub or AWS.

Permissions comprise the following properties

  • The action defines what operations can be performed. Currently the actions read and write, where write implies that the permission can also read.
  • The entity defines the objects or resources the action can be performed on (e.g. issues, members, settings)
  • The access defines the scope or level of access. Right now this is any for all pre-defined permissions but could be extended to be more restrictive. e.g. you could introduce team access to write a permission like write any team issue

Roles

There are two roles in the initial Launchway setup.

admin

  • Has write permissions for all entities

user

  • Has write permission for issues
  • Has read permissions for members and settings

This is configured in the app/drizzle/scripts/seed.ts script and can be changed easily.

Validating roles

There is a helper method that is used at various parts of the app called validateUserRoleHasPermission(). You call it like this

const canManageUsers = await validateUserRoleHasPermission(
  userId,
  ['write'],
  'members',
)
if (!canManageUsers) {
  return redirect('/dashboard/members')
}

This will check that the current users role within the organization has write permission for settings. Both write and settings here are type-safe enums which make it easy to extend the system.

Extending the system

As you add more entities to your app, you may wish to add more role and permissions around them. There's a helper script you can run with npm setup:permissions to guide you through the process of adding new roles and permissions.

Organization-specific roles

The default roles and permissions are global and not tied to any specific organizationId. If you wanted to allow organizations to create their own roles or permissions, you could replicate the RolesTable and PermissionsTable with the addition of a new organizationId column and query this alongside, or instead of, the existing roles and permissions tables.