Permissions & RBAC

Control what each user can do and access with the permission system

Permission Types

Stack supports two types of permissions:

  1. Team Permissions: Control what a user can do within a specific team
  2. User Permissions: Control what a user can do globally, across the entire project

Both permission types can be managed from the dashboard, and both support arbitrary nesting.

Team Permissions

Team permissions control what a user can do within each team. You can create and assign permissions to team members from the Stack dashboard. These permissions could include actions like create_post or read_secret_info, or roles like admin or moderator. Within your app, you can verify if a user has a specific permission within a team.

Permissions can be nested to create a hierarchical structure. For example, an admin permission can include both moderator and user permissions. We provide tools to help you verify whether a user has a permission directly or indirectly.

Creating a Permission

To create a new permission, navigate to the Team Permissions section of the Stack dashboard. You can select the permissions that the new permission will contain. Any permissions included within these selected permissions will also be recursively included.

System Permissions

Stack comes with a few predefined team permissions known as system permissions. These permissions start with a dollar sign ($). While you can assign these permissions to members or include them within other permissions, you cannot modify them as they are integral to the Stack backend system.

Checking if a User has a Permission

To check whether a user has a specific permission, use the getPermission method or the usePermission hook on the User object. This returns the Permission object if the user has it; otherwise, it returns null. Always perform permission checks on the server side for business logic, as client-side checks can be bypassed. Here’s an example:

Check user permission on the client
1"use client";
2import { useUser } from "@stackframe/stack";
3
4export function CheckUserPermission() {
5 const user = useUser({ or: 'redirect' });
6 const permission = user.usePermission('read');
7
8 // Don't rely on client-side permission checks for business logic.
9 return (
10 <div>
11 {permission ? 'You have the read permission' : 'You shall not pass'}
12 </div>
13 );
14}

Listing All Permissions of a User

To get a list of all permissions a user has, use the listPermissions method or the usePermissions hook on the User object. This method retrieves both direct and indirect permissions. Here is an example:

List user permissions on the client
1"use client";
2import { useUser } from "@stackframe/stack";
3
4export function DisplayUserPermissions() {
5 const user = useUser({ or: 'redirect' });
6 const permissions = user.usePermissions();
7
8 return (
9 <div>
10 {permissions.map(permission => (
11 <div key={permission.id}>{permission.id}</div>
12 ))}
13 </div>
14 );
15}

Granting a Permission to a User

To grant a permission to a user, use the grantPermission method on the ServerUser. Here’s an example:

1const team = await stackServerApp.getTeam('teamId');
2const user = await stackServerApp.getUser();
3await user.grantPermission(team, 'read');

Revoking a Permission from a User

To revoke a permission from a user, use the revokePermission method on the ServerUser. Here’s an example:

1const team = await stackServerApp.getTeam('teamId');
2const user = await stackServerApp.getUser();
3await user.revokePermission(team, 'read');

User Permissions

User permissions are global permissions that apply to a user across the entire project, regardless of team context. These permissions are useful for handling things like premium plan subscriptions or global admin access.

Creating a User Permission

To create a new user permission, navigate to the User Permissions section of the Stack dashboard. Similar to team permissions, you can select other permissions that the new permission will contain, creating a hierarchical structure.

Checking if a User has a User Permission

To check whether a user has a specific user permission, use the getUserPermission method or the useUserPermission hook. Here’s an example:

Check user permission on the client
1"use client";
2import { useUser } from "@stackframe/stack";
3
4export function CheckGlobalPermission() {
5 const user = useUser({ or: 'redirect' });
6 const permission = user.useUserPermission('access_admin_dashboard');
7
8 return (
9 <div>
10 {permission ? 'You can access the admin dashboard' : 'Access denied'}
11 </div>
12 );
13}

Listing All User Permissions

To get a list of all global permissions a user has, use the listUserPermissions method or the useUserPermissions hook:

List global permissions on the client
1"use client";
2import { useUser } from "@stackframe/stack";
3
4export function DisplayGlobalPermissions() {
5 const user = useUser({ or: 'redirect' });
6 const permissions = user.useUserPermissions();
7
8 return (
9 <div>
10 {permissions.map(permission => (
11 <div key={permission.id}>{permission.id}</div>
12 ))}
13 </div>
14 );
15}

Granting a User Permission

To grant a global permission to a user, use the grantUserPermission method:

1const user = await stackServerApp.getUser();
2await user.grantUserPermission('access_admin_dashboard');

Revoking a User Permission

To revoke a global permission from a user, use the revokeUserPermission method:

1const user = await stackServerApp.getUser();
2await user.revokeUserPermission('access_admin_dashboard');

By following these guidelines, you can efficiently manage and verify both team and user permissions within your application.