Permissions, sorted
Roles that nest·One check, server or client·Managed from the dashboard
Ask whether a user can do something — get an answer
Same call on server and client·Inheritance handled for you·Project-wide or per-team
ts
1"use server";2import { stackServerApp } from "@/stack";3 4export async function inviteMember(teamId: string, email: string) {5 const user = await stackServerApp.getUser({ or: "throw" });6 const team = await user.getTeam(teamId);7 8 // Returns the permission if the user has it, null otherwise.9 if (!(await user.getPermission(team, "$invite_members"))) {10 throw new Error("Not allowed");11 }12 await team.inviteUser({ email });13}Roles without the wiring
Define them in the dashboard·Check them anywhere in your code·Let them nest, naturally
Acme team/Members
Signed in as
MV
Mira (viewer)
Viewer · 1 permissions
user.usePermissionchecking
const canInvite =
user.usePermission(team, "$invite_members");
Members · 4
LP
Lia ParkAdminNR
Noah ReyesMemberAK
Alex KimMemberKS
Kai SinghViewer01·Permission checks
One line decides what shows up
- Ask the same question on the server and in your React components
- Buttons that need a permission hide themselves — no flicker
- Server-side checks keep the real enforcement honest
Server & clientReactive UIOne API
Noah·Acme team
Role definition · admincontains 4
adminparent
└─moderator
└─$invite_members
└─$read_members
└─$update_team
Grant admin to Noah
user.grantPermission(team, "admin")
Effective permissions
No permissions yet
02·Nested roles
Roles that contain other roles
- Build an admin role from smaller, named permissions
- Grant the parent once — every nested permission comes along
- Drop a permission into a role and every member picks it up
Nested permissionsInheritanceOne source of truth
Mira·Effective permissions
AC
Acme
5 perms
GX
Globex
1 perms
Team scope· changes per team
usePermission(team, …)$update_team$invite_members$read_members$remove_membersbilling
$built-inStack Auth ships these for every team
Project scope· follows the user
usePermission(…)staffbeta_tester
Same across Acme, Globex, every team
Pass a team for team-scoped. Drop it for project-wide.
03·Per-team and project-wide
Some permissions belong to a team. Some belong to everyone.
- Team permissions live inside a team — admin of Acme, member of Globex
- Project permissions apply across your whole app — staff, beta, premium
- Same check, just pass a team or don't
- Built-in team permissions cover invites, member management, and team settings
Team scopeProject scopeBuilt-ins included
Ready to lock things down?
Drop in a single app — or use the whole platform. Either way, you ship faster.
Get started for free