Team Concepts
What is a Team?
A Team represents a group of users working together within your application. Teams enable:- Multi-tenancy (users belong to multiple organizations)
- Team-specific data isolation
- Role-based access within teams
- Collaborative features
- Each team has a unique ID across the project
- Teams are associated with a specific branch (usually “main”)
- Teams can have custom metadata (client, server, read-only)
- Users can be members of multiple teams simultaneously
Team Membership
TeamMember represents a user’s membership in a specific team:- Links a
ProjectUserto aTeam - Can override user’s display name and profile image for that team
- Stores team-specific permissions
- Tracks whether this team is the user’s selected team
Selected Team
Users can have one selected team at a time:- Used as the default team for operations
- Included in JWT access token (
selected_team_id) - Unique constraint ensures only one selected team per user
- Can be updated via API
/apps/backend/prisma/schema.prisma:143.
Team Operations
Creating a Team
Create a new team with the current user as the creator:Team creation
A
Team record is created with:- Unique team ID
- Display name
- Profile image (uploaded to S3 if base64)
- Metadata fields
- Mirrored project/branch IDs for uniqueness constraints
Creator added as member
If
creator_user_id is provided, a TeamMember record is created linking the user to the team with type: 'creator'.Default permissions granted
Team creator receives default permissions from config:Typically includes:
$update_team$delete_team$invite_members$remove_members$manage_api_keys
/apps/backend/src/app/api/latest/teams/crud.tsx:38.
With client authentication, users can only create teams if
allowClientTeamCreation is enabled in the project configuration. With server/admin authentication, teams can always be created.Reading a Team
Fetch team details by ID:- Client auth: User must be a member of the team
- Server/admin auth: Any team can be accessed
/apps/backend/src/app/api/latest/teams/crud.tsx:110.
Updating a Team
Modify team information:- Client auth: User must have
$update_teampermission (recursively checked) - Server/admin auth: No permission check required
/apps/backend/src/app/api/latest/teams/crud.tsx:136.
Deleting a Team
Remove a team and all associated data:- Client auth: User must have
$delete_teampermission - Server/admin auth: No permission check required
- All
TeamMemberrecords are deleted - All
TeamMemberDirectPermissionrecords are deleted - All
ProjectApiKeyrecords for the team are deleted - Team-specific data is removed
/apps/backend/src/app/api/latest/teams/crud.tsx:182.
Listing Teams
Retrieve teams (optionally filtered by user membership):- Client auth: Must filter by current user (
user_id=me) - Server/admin auth: Can list all teams or filter by any user
/apps/backend/src/app/api/latest/teams/crud.tsx:214.
Team Memberships
Adding Users to Teams
Add a user to a team (invitation flow):TeamMember record and grants default member permissions.
Implementation:
type parameter determines which default permissions are granted:
"creator"- Gets team creator permissions"member"- Gets team member permissions
/apps/backend/src/app/api/latest/teams/crud.tsx:90.
Team Member Profiles
Each team membership can have customized profile information:displayName- Overrides user’s global display name within this teamprofileImageUrl- Overrides user’s global profile image within this team
/apps/backend/prisma/schema.prisma:143.
Selected Team
Users can mark one team as their “selected” team:- Sets
isSelected = TRUEon the specifiedTeamMember - Unsets
isSelectedon all other memberships for this user - Updates the user’s access token to include
selected_team_id
BooleanTrue enum (only values: TRUE) ensures only one selected team per user.
See model at /apps/backend/prisma/schema.prisma:157.
Team Permissions
System Team Permissions
Stack Auth includes built-in team permissions:- Cannot be modified or deleted
- Are available in all projects
- Are granted via default permission configuration
/apps/backend/src/lib/permissions.tsx:13.
Custom Team Permissions
Define custom team-scoped permissions in your project config:- Must have
scope: "team" - Can contain other team permissions
- Are granted per team membership
- Cannot contain project-scoped permissions
Granting Team Permissions
Grant a permission to a user within a specific team:TeamMemberDirectPermission record.
Requirements:
- User must be a member of the team
- Permission must exist and have
scope: "team" - System permissions (prefixed with
$) are always available
Checking Team Permissions
Verify a user has a specific team permission:recursive: true, the check includes:
- Direct permission grants
- Permissions contained by granted permissions
- Full permission hierarchy
/apps/backend/src/app/api/latest/teams/crud.tsx:144.
Team Invitations
Invite users to join teams via email:Creating an Invitation
- Creates a
VerificationCodewith typeTEAM_INVITATION - Sends an email with the invitation code
- Returns the code (for testing) or just success
- Client auth: User must have
$invite_memberspermission - Server/admin auth: No permission check
Accepting an Invitation
- Validates the verification code
- Creates user account if needed
- Adds user to the team as a member
- Grants default team member permissions
- Marks the code as used
Team API Keys
Teams can have their own API keys for programmatic access:Creating Team API Keys
ProjectApiKey record associated with the team.
Authorization:
- Client auth: User must have
$manage_api_keyspermission - Server/admin auth: No permission check
Using Team API Keys
Team API keys authenticate requests on behalf of the team:- Access to team resources
- Team-scoped operations
- No individual user context
Data Model
Team Table
TeamMember Table
TeamMemberDirectPermission Table
/apps/backend/prisma/schema.prisma:111.
Multi-Tenancy Patterns
Team Isolation
Data can be isolated per team using tenancy patterns:Selected Team Context
Use the selected team from the access token:Cross-Team Operations
When users need to access multiple teams:Best Practices
Team Creation
- Always add the creator as the first team member
- Grant appropriate creator permissions
- Consider team limits per user/project
- Validate team names for uniqueness if needed
Permission Management
- Use system permissions (
$) for common operations - Create custom permissions for domain-specific actions
- Leverage permission hierarchies for role-like behavior
- Document permission requirements in API documentation
Team Switching
- Update selected team when user explicitly switches
- Include selected team in access token for easy access
- Invalidate cached data when switching teams
- Consider using team-scoped URL patterns (e.g.,
/teams/{teamId}/...)
Invitation Flows
- Send verification codes via email
- Include team information in invitation emails
- Handle expired invitation codes gracefully
- Allow re-sending invitations
- Track invitation status and history
Data Isolation
- Always filter by
teamIdfor team-scoped data - Verify team membership before data access
- Use database indexes on
teamIdcolumns - Consider row-level security in database
- Test cross-team access carefully