Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Access Control Laravel Package

happenv-com/filament-access-control

Filament Access Control provides role and permission-based access management for Filament admin panels, letting you restrict resources, pages, and actions by user role so each admin sees only what they are allowed to access.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path from install to a working access-control screen:

  1. Install the package and its migration dependencies

    composer require happenv-com/filament-access-control
    

    The package sits on top of spatie/laravel-permission — if you don't already have it, publish and run its migrations before this package's.

  2. Register the plugin on your panel (app/Providers/Filament/AdminPanelProvider.php):

    use Happenv\FilamentAccessControl\FilamentAccessControlPlugin;
    
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->plugin(FilamentAccessControlPlugin::make());
    }
    
  3. Run migrations and seed the first admin

    php artisan migrate
    php artisan make:filament-user
    

    Then assign your first super-admin role — you need one account with full access before the resource screens become usable for everyone else.

  4. Where to look first

    • The plugin class (FilamentAccessControlPlugin) for ->navigationGroup(), ->navigationLabel(), and any enable/disable toggles.
    • config/filament-access-control.php (publish with php artisan vendor:publish --tag="filament-access-control-config") — this is where role/permission model overrides and guard names live.
    • The shipped Filament resources for Roles and Permissions; these are the screens your day-to-day work will live in.
  5. First real use case: replace ad-hoc is_admin boolean columns with roles. Create a panel_user / super_admin role pair, gate your panel with ->authGuard('web'), and use the package's permission resources to let non-developers manage access without touching code.

Implementation Patterns

Panel-level gating. The most common pattern is to register the plugin on a dedicated admin panel and gate the whole panel behind a role:

->plugin(FilamentAccessControlPlugin::make())
->authGuard('web')

Combine with Filament::auth() checks in a base PanelProvider so unprivileged users get a 403 rather than an empty navigation.

Roles as the unit of assignment, permissions as the unit of check. Assign roles to users (stable, few) and check permissions in code (granular, many). Checking roles directly in policies couples your code to seed data; checking permissions decouples it. Reserve ->hasRole() for panel-access decisions and use can('posts.update') everywhere else.

Resource-level enforcement. Pair the package's permission model with Filament's native authorization. Override canViewAny(), canCreate(), etc. on your own resources and map them to permission names, so the permission list in the UI directly corresponds to something the app enforces. Without this, permissions become decorative.

Seed roles and permissions idempotently. Use Permission::findOrCreate() / Role::findOrCreate() inside a seeder rather than create(). This lets you re-run seeders on deploy after adding a new permission without blowing up on duplicates — the standard failure mode of permission seeders in CI.

Multi-guard setups. If you run separate web and admin guards, define each guard's role/permission sets deliberately and set the guard on the plugin/config. Filament resources resolve against the panel's guard, so a mismatch produces the confusing "role exists but user has no permissions" symptom.

Customizing icons (new in v3.6.0). Previously the plugin's icons were hardcoded in the resource/action definitions. They are now exposed as Filament icon aliases, so you can override them the standard Filament way instead of subclassing resources:

use Filament\Support\Facades\FilamentIcon;

FilamentIcon::register([
    // alias as documented by the package for its resource/action icons
    '...' => 'heroicon-o-shield-check',
]);

Put this in a service provider's boot(). This is the cleanest extension point if you're matching an existing icon set or a design system.

Caching. Spatie's permission cache is the lever for performance. In tests, call app(PermissionRegistrar::class)->forgetCachedPermissions() after creating roles in setUp() — otherwise a test that creates a role in one test can leak a stale cache into the next.

Gotchas and Tips

Permission cache invalidation is the #1 source of "it works in tinker but not in the browser." Spatie caches the permission map; changes made directly in the database (raw SQL, a data migration, a manual insert) do not bust it. Always mutate through the Eloquent models, or call php artisan permission:cache-reset after out-of-band changes.

Guard mismatch. Role::create(['name' => 'admin']) defaults to the configured default guard. If your panel uses a different guard than config('auth.defaults.guard'), roles silently won't match. Pass 'guard_name' => 'web' explicitly in seeders and migrations to be safe.

Deleting a role cascades. Removing a role strips it from all users; removing a permission strips it from all roles. There is no undo. Before letting non-developers into the Roles resource, consider whether DeleteAction should be disabled for roles that appear in your seeders — a ->visible(fn (Role $record) => ! in_array($record->name, config('access.protected_roles'))) guard works well.

Locking yourself out. The classic: editing the super_admin role's permissions and removing your own access mid-session. Guard against it by denying edits/deletes on the role the current user holds, or at minimum by requiring an explicit confirmation on permission-detach actions.

Super-admin bypass. If you rely on Gate::before(fn ($user) => $user->hasRole('super_admin') ? true : null), be aware it bypasses every policy — including ones you intend to be strict. That's usually desired for a break-glass role, but it makes "why can this user do X" debugging impossible unless you remember the bypass exists. Keep the bypass role list explicit and short.

Icons (v3.6.0). Icon aliases registered via FilamentIcon::register() are resolved at render time, but panel-level ->icons() config takes precedence over facade registration in some Filament versions. If an override appears to be ignored, check for a competing entry in the panel's icons() array before assuming the alias name is wrong.

Navigation clutter. The plugin adds Roles and Permissions to navigation by default. On a panel where end users shouldn't see them, gate with ->shouldRegisterNavigation() / canViewAny() rather than just hiding links — hidden-but-reachable routes are still reachable.

Extension points worth knowing. The plugin class for panel-level configuration, the published config for model swaps (custom Role/Permission subclasses), the Filament resources for UI overrides via ->resource() replacements, and now icon aliases for pure-visual changes. Prefer these over forking the package — the v3.x line has been moving on dependency and CI hygiene, and forks diverge fast.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log