liberusoftware/roles-permissions-filament
Filament admin panel integration for the Liberu roles and permissions package, providing ready-made resources and UI components to manage roles, permissions, and user assignments directly inside your Filament app.
This package is a Filament UI layer over a separate authorization module (liberusoftware's roles/permissions capability). It almost certainly does not ship the Role/Permission models or migrations itself — those come from the core module. Install order matters.
# 1. Core authorization module first (models, migrations, gates)
composer require liberusoftware/module-roles-permissions
# 2. Then the Filament UI layer
composer require liberusoftware/roles-permissions-filament
php artisan migrate
php artisan filament:assets
Register the plugin on the panel(s) that should manage roles:
// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(\Liberusoftware\RolesPermissionsFilament\RolesPermissionsPlugin::make());
}
Where to look first, in this order:
composer.json — the exact Filament major (^3.0 vs ^4.0) and the core module constraint. Filament 3 → 4 broke a lot of plugin APIs; a 0-star package is likely pinned to one.src/*Plugin.php — the registration entry point and any ->roleResource() / ->permissionResource() fluent config.config/ (if published) — resource classes are often swappable here, which is your main extension seam.hasPermissionTo, Gate::allows, @can) lives there, not here.First use case: seed a handful of roles and permissions from code, log in as a super-admin, open the Roles resource, attach permissions to a role, assign that role to a user, then verify a Gate::allows('edit posts') check flips as expected. If that loop works, the wiring is sound.
Define permissions in code, assign them in the UI. The single biggest failure mode with role/permission UIs is permissions being created ad-hoc by admins and drifting from what the code actually checks. Keep an enum or config array as the source of truth and sync it in a seeder:
// config/permissions.php
return [
'posts.view', 'posts.create', 'posts.update', 'posts.delete',
'users.manage',
];
foreach (config('permissions') as $name) {
Permission::firstOrCreate(['name' => $name, 'guard_name' => 'web']);
}
Then use the plugin purely for role composition and user assignment. Restrict the Permission resource to super-admins (canCreate(): bool => false) if the core module allows it.
Authorize the admin UI itself. A roles manager that anyone can open is a privilege-escalation hole. Gate the resources:
public static function canViewAny(): bool
{
return auth()->user()?->hasPermissionTo('users.manage') ?? false;
}
Do the same for the AttachAction/DetachAction on the role→permission relation, not just the resource — Filament evaluates resource-level checks and per-action checks separately.
Extend resources rather than editing vendor code. Most Filament plugins of this shape resolve their resource classes from config or via a static property. Swap in a subclass to add tenant scoping or extra columns:
class RoleResource extends \Liberusoftware\RolesPermissionsFilament\Resources\RoleResource
{
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->where('team_id', Filament::getTenant()?->id);
}
}
Keep the authorization call site in policies. The plugin manages data; your app should still authorize through policies and gates. Don't sprinkle $user->roles->contains(...) through controllers — route everything through Gate::allows() / @can so a later swap of the underlying authorization module doesn't ripple.
Multi-panel setups. If you have separate Admin and App panels, register the plugin only on the admin panel, and make sure the core module's guard matches the panel's auth guard.
Filament-native integration points worth wiring up:
->visible(fn () => Gate::allows(...)) on actions/table columns.->authorize() on custom pages.guard_name = 'web' won't resolve for sanctum/api authenticated users. Check the core module's default guard config and the panel's ->authGuard(). Symptom: permissions show in the UI, Gate::allows() always returns false.roles / permissions / model_has_roles tables are missing after install, you installed only the Filament layer or didn't publish the core module's migrations. php artisan vendor:publish --tag=... then migrate.resetCache/forgetCachedPermissions call or an artisan command). Tests that pass locally and fail in CI are usually stale cache, not logic.Gate::before for a super-admin role. If it does, Gate::allows() will return true for everything and your tests won't catch a missing permission. Test with a non-super-admin user.composer why-not filament/filament.composer.json ("1.2.3", not "^1.0").Plugin class source — it's a small package, this takes ten minutes.packages/ and path-repo'ing it if you need to patch a Filament 4 incompatibility; upstream turnaround on a 0-star repo is unpredictable.app/Filament/Resources. If you subclass the plugin's RoleResource, register only one of them or you'll get duplicate navigation entries and ambiguous route names.php artisan filament:optimize-clear, confirm the plugin is on the correct panel provider, confirm ->plugin() is before resource registration in the chain, and check php artisan about for the resolved panel config.vendor/.The package is a thin, useful convenience if the underlying authorization module is one you've already committed to. It is not a substitute for reading that module's permission-check API — that's where the actual behavior lives.
How can I help you explore Laravel packages today?