| Recommend this page to a friend! |
| Info | Documentation | Reputation | Support forum | Blog | Links |
| Last Updated | Ratings | Unique User Downloads | Download Rankings | |||||
| 2025-12-02 (12 days ago) | Not yet rated by the users | Total: Not yet counted | Not yet ranked | |||||
| Version | License | PHP version | Categories | |||
| laravelteamspermissi 1.0 | MIT/X Consortium ... | 7 | User Management, Libraries, PHP 7 |
| Description | Authors Alberto Rial Barreiro Contributor | |
This package can manage user and group permissions in Laravel applications. |
Please read this document to learn how to set up and configure user and group permissions in Laravel applications.
A comprehensive Laravel package designed for advanced team-based permission management in multi-tenant applications based on [Jurager/Teams]. This package provides a flexible and powerful system for organizing users into teams, assigning granular permissions through roles and groups, and managing entity-specific access controls.
Core Functionality:
composer require squareetlabs/laravel-teams-permissions
php artisan vendor:publish --provider="Squareetlabs\LaravelTeamsPermissions\TeamsServiceProvider"
This will publish:
- config/teams.php - Configuration file
- Database migrations
Add the HasTeams trait to your User model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Squareetlabs\LaravelTeamsPermissions\Traits\HasTeams;
class User extends Model
{
use HasTeams;
// ... rest of your code
}
> ?? IMPORTANT: Always do backups before running migrations.
php artisan migrate
> [!NOTE]
> If you wish to use custom foreign keys and table names, modify config/teams.php before running migrations.
To improve performance, enable caching in .env:
TEAMS_CACHE_ENABLED=true
TEAMS_CACHE_DRIVER=redis
TEAMS_CACHE_TTL=3600
To log all team actions:
TEAMS_AUDIT_ENABLED=true
TEAMS_AUDIT_LOG_CHANNEL=teams
> [!NOTE]
> If you enable audit logging after running migrations, you'll need to publish and run the audit migration:
> `bash
> php artisan vendor:publish --tag=teams-migrations
> php artisan migrate
> `
To expose a REST API for team management:
TEAMS_API_ENABLED=true
The configuration file config/teams.php contains all options:
'models' => [
'user' => App\Models\User::class,
'team' => Squareetlabs\LaravelTeamsPermissions\Models\Team::class,
// ... other models
],
'cache' => [
'enabled' => env('TEAMS_CACHE_ENABLED', true),
'driver' => env('TEAMS_CACHE_DRIVER', 'redis'),
'ttl' => env('TEAMS_CACHE_TTL', 3600),
'prefix' => 'teams_permissions',
'tags' => true,
],
'audit' => [
'enabled' => env('TEAMS_AUDIT_ENABLED', false),
'log_channel' => env('TEAMS_AUDIT_LOG_CHANNEL', 'teams'),
'events' => [
'role_assigned',
'permission_granted',
'permission_revoked',
'team_member_added',
'team_member_removed',
],
],
See config/teams.php for all available options.
use Squareetlabs\LaravelTeamsPermissions\Models\Team;
$team = Team::create([
'name' => 'My Team',
'user_id' => auth()->id(),
]);
// Add role with permissions
$team->addRole('admin', [
'posts.*',
'users.*',
'settings.edit',
], 'Administrator', 'Role with all permissions');
$team->addRole('editor', [
'posts.view',
'posts.create',
'posts.edit',
], 'Editor', 'Can manage posts');
// Add user with a role
$team->addUser($user, 'editor');
// Update user's role
$team->updateUser($user, 'admin');
// Remove user
$team->deleteUser($user);
// Check if user has a permission
if ($user->hasTeamPermission($team, 'posts.create')) {
// User can create posts
}
// Check if user has a role
if ($user->hasTeamRole($team, 'admin')) {
// User is admin
}
// Check specific ability on an entity
if ($user->hasTeamAbility($team, 'edit', $post)) {
// User can edit this specific post
}
// Access the team's owner
$team->owner
// Get all team users (excluding owner)
$team->users()
// Get all users including owner
$team->allUsers()
// Check if a user belongs to the team
$team->hasUser($user)
// Add user with a role (by ID or code)
$team->addUser($user, 'admin')
// Update user's role
$team->updateUser($user, 'editor')
// Remove user from team
$team->deleteUser($user)
// Invite user by email
$team->inviteUser('[email protected]', 'member')
// Accept invitation
$team->inviteAccept($invitation_id)
// Get all team abilities
$team->abilities()
// Get all team roles
$team->roles()
// Get user's role in the team
$team->userRole($user)
// Check if team has a role
$team->hasRole('admin') // or null to check if has any role
// Get role by ID or code
$team->getRole('admin')
// Add new role
$team->addRole($code, $permissions, $name, $description)
// Update role
$team->updateRole('admin', $newPermissions, $name, $description)
// Delete role
$team->deleteRole('admin')
// Get all groups
$team->groups()
// Get group by ID or code
$team->getGroup('moderators')
// Add new group
$team->addGroup($code, $permissions, $name)
// Update group
$team->updateGroup('moderators', $newPermissions, $name)
// Delete group
$team->deleteGroup('moderators')
// Check if team has user with email
$team->hasUserWithEmail('[email protected]')
// Check if user has permission in team
$team->userHasPermission($user, 'posts.create', $require = false)
// Get all invitations
$team->invitations()
The HasTeams trait provides the following methods:
// Get teams the user belongs to
$user->teams
// Get teams the user owns
$user->ownedTeams
// Get all teams (owned and belongs to)
$user->allTeams()
// Check if user owns a team
$user->ownsTeam($team)
// Check if user belongs to a team
$user->belongsToTeam($team)
// Get user's role in a team
$user->teamRole($team)
// Check if user has a role (or roles) in a team
// $require = true: all roles are required
// $require = false: at least one of the roles
$user->hasTeamRole($team, 'admin', $require = false)
$user->hasTeamRole($team, ['admin', 'editor'], $require = false)
// Get all user's permissions for a team
// $scope: 'role', 'group', or null for all
$user->teamPermissions($team, $scope = null)
// Check if user has a permission (or permissions) in a team
// $require = true: all permissions are required
// $require = false: at least one of the permissions
// $scope: 'role', 'group', or null for all
$user->hasTeamPermission($team, 'posts.create', $require = false, $scope = null)
$user->hasTeamPermission($team, ['posts.create', 'posts.edit'], $require = false)
// Get user's abilities for a specific entity
$user->teamAbilities($team, $entity, $forbidden = false)
// Check if user has an ability on an entity
$user->hasTeamAbility($team, 'edit', $post)
// Allow ability for user on an entity
$user->allowTeamAbility($team, 'edit', $post)
// Forbid ability for user on an entity
$user->forbidTeamAbility($team, 'edit', $post)
// Delete ability
$user->deleteTeamAbility($team, 'edit', $post)
// Scope for eager loading permissions
User::withTeamPermissions()->get()
$team->addRole('admin', [
'posts.*', // All post permissions
'users.view', // View users
'users.create', // Create users
'users.edit', // Edit users
'users.delete', // Delete users
'settings.*', // All settings permissions
], 'Administrator', 'Role with full access');
You can use wildcards for permissions:
// Check simple permission
if ($user->hasTeamPermission($team, 'posts.create')) {
// User can create posts
}
// Check multiple permissions (OR)
if ($user->hasTeamPermission($team, ['posts.create', 'posts.edit'], false)) {
// User can create OR edit posts
}
// Check multiple permissions (AND)
if ($user->hasTeamPermission($team, ['posts.create', 'posts.edit'], true)) {
// User can create AND edit posts
}
You can enable wildcard permissions in configuration:
'wildcards' => [
'enabled' => true,
'nodes' => [
'*',
'.',
'all'
]
]
Users with these permissions will have full access to the team.
Abilities allow specific permissions for individual entities.
// Allow user to edit a specific post
$user->allowTeamAbility($team, 'edit', $post);
// Forbid user to edit a specific post
$user->forbidTeamAbility($team, 'edit', $post);
if ($user->hasTeamAbility($team, 'edit', $post)) {
// User can edit this specific post
}
Abilities use an access level system:
| Level | Value | Description |
|-------|-------|-------------|
| DEFAULT | 0 | No explicit permissions |
| FORBIDDEN | 1 | Access denied |
| ROLE_ALLOWED | 2 | Allowed by role |
| ROLE_FORBIDDEN | 3 | Forbidden by role |
| GROUP_ALLOWED | 4 | Allowed by group |
| GROUP_FORBIDDEN | 5 | Forbidden by group |
| USER_ALLOWED | 5 | Specifically allowed to user |
| USER_FORBIDDEN | 6 | Specifically forbidden to user |
| GLOBAL_ALLOWED | 6 | Global permissions |
Access is granted if the allowed level >= forbidden level.
Groups allow organizing users with shared permissions.
// Add group
$team->addGroup('moderators', [
'posts.moderate',
'comments.moderate',
], 'Moderators');
// Update group
$team->updateGroup('moderators', [
'posts.moderate',
'comments.moderate',
'users.moderate',
], 'Moderators');
// Delete group
$team->deleteGroup('moderators');
// Get group
$group = $team->getGroup('moderators');
// Add users to group
$group->users()->attach($user);
// or multiple users
$group->users()->attach([$user1->id, $user2->id]);
// Remove users from group
$group->users()->detach($user);
Groups without team_id are global and apply to all teams:
// Create global group (team_id = null)
$globalGroup = Group::create([
'code' => 'support',
'name' => 'Support Team',
'team_id' => null,
]);
The package provides middleware for route protection.
Middleware is automatically registered as role, permission, and ability.
// Check role
Route::middleware(['role:admin,team_id'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
// Check permission
Route::middleware(['permission:posts.create,team_id'])->group(function () {
Route::post('/posts', [PostController::class, 'store']);
});
// Check ability
Route::middleware(['ability:edit,App\Models\Post,post_id'])->group(function () {
Route::put('/posts/{post_id}', [PostController::class, 'update']);
});
// User must have admin OR root
Route::middleware(['role:admin|root,team_id'])->group(function () {
// ...
});
// User must have admin AND editor
Route::middleware(['role:admin|editor,team_id,require'])->group(function () {
// ...
});
The package includes Blade directives for permission checks in views:
{{-- Check role --}}
@teamRole($team, 'admin')
<button>Admin Panel</button>
@endteamRole
{{-- Check permission --}}
@teamPermission($team, 'posts.create')
<a href="{{ route('posts.create') }}">New Post</a>
@endteamPermission
{{-- Check ability --}}
@teamAbility($team, 'edit', $post)
<button>Edit Post</button>
@endteamAbility
The package integrates with Laravel's Policy system.
php artisan teams:policy PostPolicy --model=Post
This generates a policy extending TeamPolicy:
namespace App\Policies;
use App\Models\Post;
use Squareetlabs\LaravelTeamsPermissions\Policies\TeamPolicy;
class PostPolicy extends TeamPolicy
{
public function view(User $user, Post $post): bool
{
$team = $this->getTeamFromModel($post);
return $this->checkTeamPermission($user, $team, 'posts.view');
}
public function update(User $user, Post $post): bool
{
$team = $this->getTeamFromModel($post);
return $this->checkTeamAbility($user, $team, 'posts.update', $post);
}
}
// In a controller
if ($user->can('view', $post)) {
// User can view the post
}
// In a view
@can('update', $post)
<button>Edit</button>
@endcan
If you enable the REST API, you'll have access to complete endpoints for team management.
TEAMS_API_ENABLED=true
GET /api/teams - List teams
POST /api/teams - Create team
GET /api/teams/{team} - View team
PUT /api/teams/{team} - Update team
DELETE /api/teams/{team} - Delete team
GET /api/teams/{team}/members - List members
POST /api/teams/{team}/members - Add member
PUT /api/teams/{team}/members/{user} - Update member role
DELETE /api/teams/{team}/members/{user} - Remove member
GET /api/teams/{team}/roles - List roles
POST /api/teams/{team}/roles - Create role
PUT /api/teams/{team}/roles/{role} - Update role
DELETE /api/teams/{team}/roles/{role} - Delete role
GET /api/teams/{team}/groups - List groups
POST /api/teams/{team}/groups - Create group
PUT /api/teams/{team}/groups/{group} - Update group
DELETE /api/teams/{team}/groups/{group} - Delete group
GET /api/teams/{team}/permissions - List permissions
The API requires Sanctum authentication:
// In your frontend application
axios.get('/api/teams', {
headers: {
'Authorization': 'Bearer ' + token
}
});
The package includes several useful commands:
# List all teams
php artisan teams:list
# View team details
php artisan teams:show {team}
# View team permissions
php artisan teams:permissions {team}
# Add member to team
php artisan teams:add-member {team} {user} {role}
# Sync permissions from configuration
php artisan teams:sync-permissions
# Export team permissions
php artisan teams:export-permissions {team} --format=json
# Import permissions to team
php artisan teams:import-permissions {team} --file=permissions.json
# Clear permissions cache
php artisan teams:clear-cache
# Generate a policy
php artisan teams:policy PostPolicy --model=Post
The caching system significantly improves permission check performance.
'cache' => [
'enabled' => true,
'driver' => 'redis',
'ttl' => 3600, // 1 hour
'prefix' => 'teams_permissions',
'tags' => true,
],
php artisan teams:clear-cache
Or programmatically:
use Squareetlabs\LaravelTeamsPermissions\Support\Services\PermissionCache;
$cache = new PermissionCache();
$cache->flush();
The audit system logs all important team actions.
TEAMS_AUDIT_ENABLED=true
TEAMS_AUDIT_LOG_CHANNEL=teams
use Squareetlabs\LaravelTeamsPermissions\Models\TeamAuditLog;
// Get logs for a team
$logs = TeamAuditLog::where('team_id', $team->id)->get();
// Get logs for a user
$logs = TeamAuditLog::where('user_id', $user->id)->get();
// Get logs for a specific action
$logs = TeamAuditLog::where('action', 'team_member_added')->get();
> [!NOTE]
> If you enable audit logging after running migrations, you'll need to run:
> `bash
> php artisan vendor:publish --tag=teams-migrations
> php artisan migrate
> `
The package fires events for important actions:
use Squareetlabs\LaravelTeamsPermissions\Events\TeamMemberAdded;
use Squareetlabs\LaravelTeamsPermissions\Events\TeamMemberRemoved;
Event::listen(TeamMemberAdded::class, function ($team, $user) {
// Notify user they were added
});
Event::listen(TeamMemberRemoved::class, function ($team, $user) {
// Notify user they were removed
});
The package includes validation rules:
use Squareetlabs\LaravelTeamsPermissions\Rules\ValidPermission;
$request->validate([
'permission' => ['required', new ValidPermission()],
]);
// Create team
$team = Team::create([
'name' => 'Blog Team',
'user_id' => auth()->id(),
]);
// Add roles
$team->addRole('editor', ['posts.*', 'comments.moderate'], 'Editor');
$team->addRole('author', ['posts.create', 'posts.edit'], 'Author');
$team->addRole('viewer', ['posts.view'], 'Viewer');
// In a controller
public function store(Request $request)
{
$team = Team::find($request->team_id);
if (!auth()->user()->hasTeamPermission($team, 'posts.create')) {
abort(403);
}
// Create post...
}
// Each client has their own team
$clientTeam = Team::create([
'name' => $client->name,
'user_id' => $client->owner_id,
]);
// Client-specific roles
$clientTeam->addRole('admin', ['*'], 'Administrator');
$clientTeam->addRole('user', ['dashboard.view', 'reports.view'], 'User');
// Check access in middleware
Route::middleware(['permission:dashboard.view,team_id'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
The package includes factories and seeders for testing:
use Squareetlabs\LaravelTeamsPermissions\Database\Factories\TeamFactory;
$team = TeamFactory::new()
->withRoles()
->withGroups()
->create();
Make sure your User model is configured in config/teams.php:
'models' => [
'user' => App\Models\User::class,
],
If you enable audit logging after running migrations:
php artisan vendor:publish --tag=teams-migrations
php artisan migrate
Or disable audit logging in config/teams.php:
'audit' => [
'enabled' => false,
],
Clear cache manually:
php artisan teams:clear-cache
HasTeams TraitMethods available on User model:
HasMembers TraitMethods available on Team model:
PermissionCache ServiceAuditService ServiceTeamPolicy Base ClassContributions are welcome. Please:
See CHANGELOG.md for the full list of changes.
This package is open-sourced software licensed under the MIT license.
For support, please open an issue on GitHub.
| File | Role | Description | ||
|---|---|---|---|---|
| Data | Auxiliary data | |||
| Data | Auxiliary data | |||
| Data | Auxiliary data | |||
| Lic. | License text | |||
| Data | Auxiliary data | |||
| Data | Auxiliary data | |||
| Data | Auxiliary data | |||
| Doc. | Documentation | |||
| / | database |
| File | Role | Description | ||
|---|---|---|---|---|
| / | database | / | migrations |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | resources | / | views | / | emails |
| File | Role | Description |
|---|---|---|
| |
Aux. | Configuration script |
| / | src |
| File | Role | Description | ||
|---|---|---|---|---|
| |
Class | Class source | ||
| / | src | / | Console |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Events |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Exceptions |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| / | src | / | Http | / | Controllers |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Middleware |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Models |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Rules |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Support | / | Services |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | src | / | Traits |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| / | stubs | / | app | / | Controllers |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| / | tests |
| / | tests | / | Feature |
| File | Role | Description | ||
|---|---|---|---|---|
| |
Class | Class source | ||
| |
Class | Class source | ||
| / | tests | / | Feature | / | Middleware |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | tests | / | Unit |
| / | tests | / | Unit | / | Models |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| |
Class | Class source |
| / | tests | / | Unit | / | Services |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| / | tests | / | Unit | / | Traits |
| File | Role | Description |
|---|---|---|
| |
Class | Class source |
| |
Class | Class source |
| The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page. |
| Version Control | Unique User Downloads | |||||||
| 100% |
|
| Applications that use this package |
If you know an application of this package, send a message to the author to add a link here.