laraarabdev / filament-gatekeeper
Advanced Role and Permission management for Laravel Filament with Spatie Permission integration, multi-guard support, HMVC modules, and performance caching.
Package info
github.com/LaraArabDev/filament-gatekeeper
pkg:composer/laraarabdev/filament-gatekeeper
Fund package maintenance!
Requires
- php: ^8.2
- filament/filament: ^5.0
- illuminate/contracts: ^11.0|^12.0
- spatie/laravel-package-tools: ^1.15
- spatie/laravel-permission: ^6.0|^7.0
Requires (Dev)
- larastan/larastan: ^2.0|^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0|^3.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-07-25 22:28:37 UTC
README
Granular role & permission management for Laravel Filament 5.x — built to give you full control over every layer of your app with minimal setup.
Filament Gatekeeper lets you control and customize who sees and does what across your entire application — Filament resources, form fields, table columns, pages, widgets, relation managers, and API responses — all from one place.
composer require spatie/laravel-permission php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" composer require laraarabdev/filament-gatekeeper php artisan gatekeeper:install php artisan migrate php artisan gatekeeper:sync # auto-discovers all permissions
Then assign permissions to roles in the UI — no code changes needed.
What you can control:
- Resource access (view, create, edit, delete, restore...)
- Individual form fields — visible or editable per role
- Table columns — hide sensitive data by role
- Custom actions, widgets, pages, and relation managers
- API responses — filter fields and relations per role
- Multi-guard support (web + API)
- Super admin role that bypasses all checks
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Default Setup Options
- Usage
- Auto-Discovery (Field & Column Detection)
- Permission Management
- API Permissions
- Commands
- Quick Reference
- Contributing
- License
Features
Supported Languages: English, Arabic, French, Spanish, Portuguese, German, Italian, Dutch, Russian, Chinese, Japanese, Korean, Indonesian, Polish, Hindi, Ukrainian, Turkish, Persian
Requirements
- PHP 8.2, 8.3, or 8.4
- Laravel 11.x or 12.x
- Filament 5.x (latest: 5.6.3)
- Spatie Laravel Permission 6.x (must be installed and configured)
Compatibility Matrix
| Filament | Laravel 11 | Laravel 12 |
|---|---|---|
| 5.6.x (latest stable) | PHP 8.2, 8.3, 8.4 | PHP 8.2, 8.3, 8.4 |
| ^5.0 (any 5.x) | PHP 8.2, 8.3, 8.4 | PHP 8.2, 8.3, 8.4 |
All combinations are verified in CI on every push.
Installation
# 1. Install & publish Spatie Permission (required dependency) composer require spatie/laravel-permission php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" # 2. Install Gatekeeper composer require laraarabdev/filament-gatekeeper php artisan gatekeeper:install php artisan migrate php artisan gatekeeper:sync
The install command publishes the config, migrations, and updates config/permission.php automatically.
Quick Start
1. Register the Plugin
In your Filament Panel Provider (app/Providers/Filament/AdminPanelProvider.php):
use LaraArabDev\FilamentGatekeeper\GatekeeperPlugin; public function panel(Panel $panel): Panel { return $panel ->plugins([ GatekeeperPlugin::make() ->superAdminRole('super-admin') ->bypassForSuperAdmin(true) ->enableFieldPermissions() ->enableColumnPermissions() ->enableActionPermissions() ->enableRelationPermissions() ->navigationGroup('Access Control'), ]); }
2. Add HasRoles to User Model
Option A: Extend Base Class (Recommended)
use LaraArabDev\FilamentGatekeeper\Base\GatekeeperAuthenticatable; class User extends GatekeeperAuthenticatable { // HasRoles trait is automatically included! }
Option B: Use Trait Manually
use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { use HasRoles; }
3. Apply Permissions to Resources
Option A: Extend Base Class (Recommended)
use LaraArabDev\FilamentGatekeeper\Base\GatekeeperResource; class UserResource extends GatekeeperResource { protected static ?string $model = User::class; // All permissions work automatically! }
Option B: Use Traits
use Filament\Resources\Resource; use LaraArabDev\FilamentGatekeeper\Concerns\HasResourcePermissions; class UserResource extends Resource { use HasResourcePermissions; protected static ?string $model = User::class; }
4. Sync Permissions
php artisan gatekeeper:sync
Or use the dashboard action in the Role Resource.
5. Assign Roles to Users
Navigate to the Roles page in your Filament panel, assign permissions to roles, then assign roles to users.
Configuration
The configuration file is located at config/gatekeeper.php. Key settings:
return [ 'super_admin' => [ 'enabled' => true, 'role' => 'super-admin', ], 'guards' => [ 'web' => ['enabled' => true], 'api' => ['enabled' => true], ], 'field_permissions' => [ 'User' => ['email', 'password', 'salary', 'phone'], ], 'column_permissions' => [ 'User' => ['email', 'phone', 'salary', 'created_at'], ], 'custom_actions' => [ 'User' => ['export', 'impersonate', 'suspend'], ], 'relation_permissions' => [ 'User' => ['roles', 'posts', 'orders'], ], 'field_discovery' => [ 'enabled' => true, 'sources' => ['fillable'], ], 'column_discovery' => [ 'enabled' => true, 'sources' => ['config', 'database'], ], ];
Default Setup Options
All options are in config/gatekeeper.php. Below is a complete reference of every available setting.
Super Admin
| Key | Default | Description |
|---|---|---|
super_admin.enabled |
true |
Enable super admin bypass for all permission checks |
super_admin.role |
'super-admin' |
Role name that bypasses all checks |
Guards
| Key | Default | Options | Description |
|---|---|---|---|
guard |
'web' |
'web', 'api', any guard name |
Default guard used for permission checks |
guards.web.enabled |
true |
true, false |
Enable web guard |
guards.web.provider |
'users' |
Any auth provider | User provider for web guard |
guards.api.enabled |
true |
true, false |
Enable API guard |
guards.api.provider |
'users' |
Any auth provider | User provider for API guard |
Discovery Paths
| Key | Default | Description |
|---|---|---|
discovery.discover_models |
false |
Auto-discover API-only models (no Filament resource) |
discovery.models |
['app/Models'] |
Paths to scan for models |
discovery.resources |
['app/Filament/Resources', 'app/Filament/*/Resources'] |
Paths to scan for Filament resources |
discovery.pages |
['app/Filament/Pages', 'app/Filament/*/Pages'] |
Paths to scan for Filament pages |
discovery.widgets |
['app/Filament/Widgets', 'app/Filament/*/Widgets'] |
Paths to scan for Filament widgets |
HMVC Modules (nwidart/laravel-modules)
| Key | Default | Description |
|---|---|---|
modules.enabled |
false |
Enable module discovery |
modules.namespace |
'Modules' |
Root namespace for modules |
modules.path |
base_path('Modules') |
Root path for modules |
modules.discovery_paths.models |
'{module}/Models' |
Model path pattern inside each module |
modules.discovery_paths.resources |
'{module}/Filament/Resources' |
Resource path pattern |
modules.discovery_paths.pages |
'{module}/Filament/Pages' |
Page path pattern |
modules.discovery_paths.widgets |
'{module}/Filament/Widgets' |
Widget path pattern |
Navigation
| Key | Default | Description |
|---|---|---|
navigation.group |
'Access Control' |
Sidebar group for Gatekeeper resources |
navigation.icon |
'heroicon-o-shield-check' |
Icon for navigation items |
navigation.sort |
1 |
Sort order within the navigation group |
Cache
| Key | Default | Description |
|---|---|---|
cache.enabled |
true |
Enable permission caching |
cache.driver |
null |
Cache driver (null = default app driver) |
cache.prefix |
'gatekeeper' |
Cache key prefix |
cache.ttl |
3600 |
Cache TTL in seconds (1 hour) |
cache.tags |
['gatekeeper'] |
Cache tags (requires tagged driver like Redis) |
Permission Generator
| Key | Default | Options | Description |
|---|---|---|---|
generator.snake_case |
true |
true, false |
Use snake_case names (view_any_user vs viewAnyUser) |
generator.separator |
'_' |
Any string | Separator between permission parts |
generator.include_guard |
false |
true, false |
Append guard name to permission (e.g. view_any_user_web) |
Exclusion Lists
| Key | Default | Description |
|---|---|---|
excluded_models |
[] |
Models to skip during permission discovery |
excluded_resources |
[] |
Filament resources to skip |
excluded_pages |
[] |
Filament pages to skip |
excluded_widgets |
[] |
Filament widgets to skip |
Usage
Resource Permissions
When using HasResourcePermissions trait or extending GatekeeperResource, these methods are automatically implemented:
| Method | Description |
|---|---|
canViewAny() |
Check if user can view any records |
canView($record) |
Check if user can view a specific record |
canCreate() |
Check if user can create records |
canEdit($record) |
Check if user can edit a record |
canDelete($record) |
Check if user can delete a record |
canRestore($record) |
Check if user can restore a record |
canForceDelete($record) |
Check if user can force delete a record |
canReplicate($record) |
Check if user can replicate a record |
canReorder() |
Check if user can reorder records |
Generated permissions: view_any_user, view_user, create_user, update_user, delete_user, restore_user, force_delete_user, replicate_user, reorder_user
Field Permissions
Control visibility and editability of form fields:
use LaraArabDev\FilamentGatekeeper\Concerns\HasFieldPermissions; class UserResource extends Resource { use HasFieldPermissions; public static function form(Schema $schema): Schema { return $schema->schema([ TextInput::make('name'), TextInput::make('email') ->visible(fn () => static::canViewField('email')) ->disabled(fn () => !static::canUpdateField('email')), TextInput::make('salary') ->visible(fn () => static::canViewField('salary')) ->disabled(fn () => !static::canUpdateField('salary')), ]); } }
Generated permissions: view_field_user_email, update_field_user_email, view_field_user_salary, update_field_user_salary
Column Permissions
Control table column visibility:
use LaraArabDev\FilamentGatekeeper\Concerns\HasColumnPermissions; class UserResource extends Resource { use HasColumnPermissions; public static function table(Table $table): Table { return $table->columns([ TextColumn::make('name'), TextColumn::make('email') ->visible(fn () => static::canViewColumn('email')), TextColumn::make('salary') ->visible(fn () => static::canViewColumn('salary')), ]); } }
Generated permissions: view_column_user_email, view_column_user_salary
Action Permissions
Control custom action execution:
use LaraArabDev\FilamentGatekeeper\Concerns\HasActionPermissions; class UserResource extends Resource { use HasActionPermissions; public static function table(Table $table): Table { return $table->actions([ Action::make('export') ->visible(fn () => static::canExecuteAction('export')), ]); } }
Generated permissions: execute_user_export_action
Page Permissions
Control access to custom Filament pages:
use LaraArabDev\FilamentGatekeeper\Base\GatekeeperPage; class SettingsPage extends GatekeeperPage { protected static string $view = 'filament.pages.settings'; // canAccess() works automatically }
Generated permissions: view_settings_page
Widget Permissions
Control widget visibility:
use LaraArabDev\FilamentGatekeeper\Base\GatekeeperWidget; class StatsOverview extends GatekeeperWidget { // canView() works automatically }
Generated permissions: view_stats_overview_widget
Relation Permissions
Control access to relation managers:
use LaraArabDev\FilamentGatekeeper\Concerns\HasRelationPermissions; class UserResource extends Resource { use HasRelationPermissions; public static function getRelations(): array { return static::getPermittedRelations([ RolesRelationManager::class, PostsRelationManager::class, ]); } }
Generated permissions: view_relation_user_roles, view_relation_user_posts
Auto-Discovery — Field & Column Detection
Filament Gatekeeper can automatically discover which fields and columns need permissions, so you don't have to list them manually. Discovery is configured separately for fields (form inputs) and columns (table display).
Key concept: When you enable discovery, Gatekeeper scans your application using one or more sources and generates permissions for every discovered field/column. You control which sources are used, what order they're checked, and which fields/columns to exclude.
How It Works
1. You enable discovery in config/gatekeeper.php
2. You choose one or more sources (e.g., fillable, database, resource)
3. Run `php artisan gatekeeper:sync`
4. Gatekeeper scans each source, merges results, removes duplicates & exclusions
5. Permissions are created in the database
When multiple sources are configured, results from all sources are merged and deduplicated — you will never get duplicate permissions even if the same field appears in multiple sources.
Field Discovery
Field discovery detects form fields that should have view and update permissions.
// config/gatekeeper.php 'field_discovery' => [ 'enabled' => true, // Set to true to activate 'sources' => ['fillable'], // One or more sources (see below) ],
Available Sources
| Source | How It Works | Best For |
|---|---|---|
fillable |
Reads the model's |
Recommended default. Fast, predictable, and only includes fields you've explicitly marked as fillable in your model. |
database |
Queries the database schema using |
Full coverage of all database columns. Use when you want permissions for every column, not just fillable ones. Pair with exclusions to filter out system columns. |
resource |
Parses the PHP source code of the Filament Resource's |
Matches permissions exactly to your Filament form definition. Only fields that actually appear in the UI get permissions. |
config |
Reads from the |
Full manual control. Use when you want to explicitly list every field per model. Useful as an override alongside other sources. |
Source Combinations
You can combine multiple sources. Results are merged and deduplicated automatically.
// Only fillable fields (recommended for most apps) 'sources' => ['fillable'], // Fillable + anything listed in config 'sources' => ['fillable', 'config'], // Everything in the database (minus exclusions) 'sources' => ['database'], // Only fields that appear in your Filament forms 'sources' => ['resource'], // All sources — maximum coverage 'sources' => ['fillable', 'database', 'resource', 'config'],
Deduplication: If
$fillableandfield_permissionsconfig, it only generates one set of permissions — never duplicates.
Excluding Fields
Control which fields are excluded from discovery at three levels:
'field_discovery' => [ // 1. Default exclusions — always removed from ALL models 'default_excluded' => [ 'id', 'uuid', 'created_at', 'updated_at', 'deleted_at', 'remember_token', 'email_verified_at', 'two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at', ], // 2. Per-model exclusions 'excluded' => [ '*' => ['password'], // Excluded from EVERY model 'User' => ['api_token'], // Excluded from User only 'Employee' => ['ssn'], // Excluded from Employee only ], ],
| Level | Key | Scope |
|---|---|---|
| Default | default_excluded |
Removed from all models — system fields like id, created_at |
| Global | excluded.* |
Removed from all models — sensitive fields like password |
| Per-model | excluded.ModelName |
Removed from a specific model only |
All three levels are combined before filtering. A field excluded at any level will not get permissions.
Sensitive Field Detection
Gatekeeper can flag fields as sensitive based on name patterns. This is used for reporting and UI indicators, not for blocking discovery.
'field_discovery' => [ 'sensitive_patterns' => [ 'password', 'secret', 'token', 'ssn', 'social_security', 'credit_card', 'cvv', 'pin', 'api_key', 'private_key', ], ],
A field is considered sensitive if its name contains any of these patterns (case-insensitive). For example, user_password_hash matches password.
Manual Field Permissions (No Discovery)
If you prefer full manual control, keep discovery disabled and list fields explicitly:
'field_discovery' => [ 'enabled' => false, // Discovery off ], 'field_permissions' => [ '*' => ['status'], // All models get 'status' permissions 'User' => ['email', 'salary', 'phone'], // User-specific fields 'Product' => ['price', 'cost', 'sku'], // Product-specific fields ],
Global
*key: Fields listed under'*'are merged into every model's field list. Duplicates are automatically removed.
Generated Permission Names
For each discovered field, Gatekeeper generates permissions using these prefixes:
| Prefix | Permission Name | Purpose |
|---|---|---|
view |
view_{model}_{field}_field |
Can the user see this field? |
update |
update_{model}_{field}_field |
Can the user edit this field? |
Example: For User model with field salary:
view_user_salary_fieldupdate_user_salary_field
Column Discovery
Column discovery detects table columns that should have view permissions.
// config/gatekeeper.php 'column_discovery' => [ 'enabled' => true, // Set to true to activate 'sources' => ['config', 'database'], // One or more sources (see below) ],
Available Sources
| Source | How It Works | Best For |
|---|---|---|
database |
Queries the database schema using |
Recommended default. Full coverage of all displayable columns. Pair with exclusions to filter out sensitive data. |
resource |
Parses the PHP source code of the Filament Resource's |
Matches permissions exactly to your Filament table definition. Only columns that actually appear in the UI get permissions. |
config |
Reads from the |
Full manual control. Use when you want to explicitly list every column per model. |
Note: Column discovery does not have a
fillablesource, because table columns are read-only and$fillableonly applies to writable attributes.
Source Combinations
// Config + database (recommended) 'sources' => ['config', 'database'], // Only columns that appear in your Filament tables 'sources' => ['resource'], // Everything in the database (minus exclusions) 'sources' => ['database'], // All sources — maximum coverage 'sources' => ['database', 'resource', 'config'],
Deduplication: Same as fields — if a column appears in multiple sources, it only generates one permission.
Excluding Columns
Control which columns are excluded from discovery at three levels:
'column_discovery' => [ // 1. Default exclusions — always removed from ALL models 'default_excluded' => [ 'password', 'remember_token', 'two_factor_secret', 'two_factor_recovery_codes', ], // 2. Per-model exclusions 'excluded' => [ '*' => [], // Excluded from EVERY model 'User' => ['api_token'], // Excluded from User only 'Employee' => ['salary'], // Excluded from Employee only ], ],
| Level | Key | Scope |
|---|---|---|
| Default | default_excluded |
Removed from all models — sensitive columns like password |
| Global | excluded.* |
Removed from all models — your custom global exclusions |
| Per-model | excluded.ModelName |
Removed from a specific model only |
Sensitive Column Detection
'column_discovery' => [ 'sensitive_patterns' => [ 'password', 'secret', 'token', 'ssn', 'salary', 'income', 'credit_card', 'bank_account', 'api_key', 'private_key', ], ],
Manual Column Permissions (No Discovery)
'column_discovery' => [ 'enabled' => false, // Discovery off ], 'column_permissions' => [ '*' => ['status'], // All models get 'status' column permission 'User' => ['email', 'salary', 'created_at'], // User-specific columns 'Employee' => ['salary', 'performance'], // Employee-specific columns ],
Generated Permission Names
For each discovered column, Gatekeeper generates permissions using this prefix:
| Prefix | Permission Name | Purpose |
|---|---|---|
view |
view_{model}_{column}_column |
Can the user see this column? |
Example: For User model with column salary:
view_user_salary_column
Field vs Column Discovery Comparison
| Feature | Field Discovery | Column Discovery |
|---|---|---|
| Available sources | fillable, database, resource, config |
database, resource, config |
| Default sources | ['fillable'] |
['config', 'database'] |
| Permission prefixes | view, update |
view |
| Permission suffix | _field |
_column |
Supports fillable source |
Yes | No |
Supports * global key |
Yes | Yes |
| Deduplication | Yes | Yes |
| Exclusions | 3 levels | 3 levels |
| Sensitive detection | Yes | Yes |
Sync Commands for Discovery
# Sync everything (including discovered fields & columns) php artisan gatekeeper:sync # Sync only field permissions php artisan gatekeeper:sync --only=fields # Sync only column permissions php artisan gatekeeper:sync --only=columns # Preview what would be synced (no database writes) php artisan gatekeeper:sync --only=fields --dry-run php artisan gatekeeper:sync --only=columns --dry-run # Sync for a specific guard php artisan gatekeeper:sync --only=fields --guard=api
Permission Management
Delete Permissions
# Delete field permissions php artisan gatekeeper:delete --type=field --model=User --force # Delete column permissions php artisan gatekeeper:delete --type=column --model=User --force # Delete all model permissions php artisan gatekeeper:delete --type=model --model=User --force # Delete orphaned permissions php artisan gatekeeper:delete --type=orphaned --force
Sync Permissions
# Sync all permissions php artisan gatekeeper:sync # Sync specific type only php artisan gatekeeper:sync --only=resources php artisan gatekeeper:sync --only=fields php artisan gatekeeper:sync --only=columns
API Permissions
Middleware
Single permission check:
Route::middleware(['auth:sanctum', 'gatekeeper.api:view_any_user'])->group(function () { Route::get('/users', [UserController::class, 'index']); });
Auto CRUD permissions:
Route::middleware(['auth:sanctum', 'gatekeeper.resource:user'])->group(function () { Route::apiResource('users', UserController::class); }); // Automatically checks: view_any_user, create_user, view_user, update_user, delete_user
Register middleware in bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'gatekeeper.api' => \LaraArabDev\FilamentGatekeeper\Http\Middleware\GatekeeperApiMiddleware::class, 'gatekeeper.resource' => \LaraArabDev\FilamentGatekeeper\Http\Middleware\GatekeeperResourceMiddleware::class, ]); })
Controller Permissions
There are four ways to handle permissions in controllers — choose the approach that fits your needs.
Option 1: Route-Level Middleware (Recommended)
Zero controller code — apply gatekeeper.resource:ModelName on your apiResource route:
Route::apiResource('users', UserController::class) ->middleware(['auth:sanctum', 'gatekeeper.resource:User']);
Auto-mapping:
| HTTP Method | URL | Permission Checked |
|---|---|---|
GET |
/users |
view_any_user |
GET |
/users/{id} |
view_user |
POST |
/users |
create_user |
PUT / PATCH |
/users/{id} |
update_user |
DELETE |
/users/{id} |
delete_user |
Your controller stays completely clean:
class UserController extends Controller { public function index() { return User::paginate(); } public function store(Request $request) { return User::create($request->validated()); } public function show(User $user) { return $user; } public function update(Request $request, User $user) { $user->update($request->validated()); return $user; } public function destroy(User $user) { $user->delete(); return response()->noContent(); } }
Option 2: Constructor-Level Middleware
Use $this->middleware() in the constructor to apply permissions once for the whole controller:
class UserController extends Controller { public function __construct() { $this->middleware('gatekeeper.resource:User'); // Or map specific methods manually $this->middleware('gatekeeper.api:view_any_user')->only('index'); $this->middleware('gatekeeper.api:create_user')->only('store'); } }
Option 3: Per-Route Middleware
Use gatekeeper.api:permission directly on individual routes for custom or non-standard routes:
Route::get('/users/export', [UserController::class, 'export']) ->middleware(['auth:sanctum', 'gatekeeper.api:execute_user_export_action']); Route::post('/users/bulk-delete', [UserController::class, 'bulkDelete']) ->middleware(['auth:sanctum', 'gatekeeper.api:delete_user']);
Option 4: Per-Method (Manual Trait)
Use HasApiPermissions trait for full control inside each method:
use LaraArabDev\FilamentGatekeeper\Concerns\HasApiPermissions; class UserController extends Controller { use HasApiPermissions; protected string $permissionModel = 'user'; public function index() { $this->authorizeIndex(); // view_any_user return User::paginate(); } public function store(Request $request) { $this->authorizeStore(); // create_user return User::create($request->validated()); } public function show(User $user) { $this->authorizeShow($user); // view_user return $user; } public function update(Request $request, User $user) { $this->authorizeUpdate($user); // update_user $user->update($request->validated()); return $user; } public function destroy(User $user) { $this->authorizeDestroy($user); // delete_user $user->delete(); return response()->noContent(); } }
Available trait methods:
| Method | Permission Checked |
|---|---|
$this->authorizeIndex() |
view_any_{model} |
$this->authorizeShow($model) |
view_{model} |
$this->authorizeStore() |
create_{model} |
$this->authorizeUpdate($model) |
update_{model} |
$this->authorizeDestroy($model) |
delete_{model} |
$this->authorizeRestore($model) |
restore_{model} |
$this->authorizeForceDelete($model) |
force_delete_{model} |
$this->authorizePermission('custom_perm') |
Any custom permission |
$this->canIndex() |
Returns bool for view_any_{model} |
$this->canStore() |
Returns bool for create_{model} |
$this->canPerform('action', $model) |
Returns bool for any action |
$this->canViewField('field') |
Returns bool for field visibility |
$this->canUpdateField('field') |
Returns bool for field editability |
$this->canViewColumn('column') |
Returns bool for column visibility |
$this->canExecuteAction('action') |
Returns bool for custom action |
$this->getVisibleFields() |
Returns array of allowed fields |
$this->getVisibleColumns() |
Returns array of allowed columns |
$this->filterByPermissions($model) |
Returns model data filtered by field permissions |
Choosing an approach:
| Approach | When to use |
|---|---|
Route middleware (gatekeeper.resource) |
Standard apiResource routes — cleanest, no controller code |
| Constructor middleware | Non-resourceful controllers or explicit per-method mapping in one place |
Per-route middleware (gatekeeper.api) |
Custom/non-standard routes with specific permissions |
| Trait per-method | When you need conditional logic, model-instance checks, or field/column filtering |
API Resources
use LaraArabDev\FilamentGatekeeper\Concerns\HasResourcePermissions; class UserResource extends JsonResource { use HasResourcePermissions; protected static string $permissionModel = 'user'; public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->whenCanViewColumn('email', $this->email), 'salary' => $this->whenCanViewColumn('salary', $this->salary), 'roles' => $this->whenCanLoadRelation('roles', fn () => $this->roles), ]; } }
Gatekeeper Facade
use LaraArabDev\FilamentGatekeeper\Facades\Gatekeeper; // Check permission if (Gatekeeper::can('view_user')) { // User has permission } // Authorize (throws exception if denied) Gatekeeper::authorize('create_user'); // Check with specific guard Gatekeeper::guard('api')->can('view_user'); // Get visible fields/columns $fields = Gatekeeper::getVisibleFields('User'); $columns = Gatekeeper::getVisibleColumns('User');
Commands
| Command | Description |
|---|---|
gatekeeper:install |
Run complete installation |
gatekeeper:sync |
Synchronize all permissions |
gatekeeper:delete |
Delete field/column/model permissions |
gatekeeper:clear-cache |
Clear permission cache |
Creating Resources, Pages & Widgets
Filament Gatekeeper does not ship its own make commands. Use Filament's built-in commands after publishing Gatekeeper's stubs so generated classes include Gatekeeper permissions:
1. Publish stubs (once):
php artisan vendor:publish --tag=gatekeeper-stubs
2. Create with Filament / Laravel:
| Command | Stub Used | Result |
|---|---|---|
php artisan make:filament-resource ModelName |
stubs/filament/Resource.stub |
Extends GatekeeperResource |
php artisan make:filament-page YourPage |
stubs/filament/Page.stub |
Adds HasPagePermissions |
php artisan make:filament-widget WidgetName |
stubs/filament/Widget.stub |
Adds HasWidgetPermissions |
Quick Reference
Permission Types
| Type | Description | Example |
|---|---|---|
resource |
Filament resource CRUD | view_any_user |
page |
Filament custom pages | view_settings_page |
widget |
Filament widgets | view_stats_overview_widget |
field |
Form field access | view_field_user_email |
column |
Table column access | view_column_user_salary |
action |
Custom actions | execute_user_export_action |
relation |
Relation managers | view_relation_user_roles |
model |
API-only models | view_product |
Traits Reference
| Trait | Purpose |
|---|---|
HasResourcePermissions |
Resource CRUD permissions |
HasFieldPermissions |
Form field permissions |
HasColumnPermissions |
Table column permissions |
HasActionPermissions |
Custom action permissions |
HasRelationPermissions |
Relation manager permissions |
HasPagePermissions |
Page access permissions |
HasWidgetPermissions |
Widget visibility permissions |
HasApiPermissions |
Controller permission helpers |
Base Classes
| Class | Extends | Purpose |
|---|---|---|
GatekeeperResource |
Filament\Resources\Resource |
Resources with permissions |
GatekeeperPage |
Filament\Pages\Page |
Pages with permissions |
GatekeeperWidget |
Filament\Widgets\Widget |
Widgets with permissions |
GatekeeperAuthenticatable |
Authenticatable |
User model with HasRoles |
GatekeeperApiResource |
JsonResource |
API resources with permissions |
Middleware
| Middleware | Alias | Purpose |
|---|---|---|
GatekeeperApiMiddleware |
gatekeeper.api |
Single permission check |
GatekeeperResourceMiddleware |
gatekeeper.resource |
Auto CRUD permissions |
Contributing
Please see DEVELOPMENT.md for details on package architecture, development setup, and contribution guidelines.
Security
If you discover any security-related issues, please email security@laraarab.dev instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see the License File for more information.