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 Simple Permissions Laravel Package

z3d0x/filament-simple-permissions

Filament Simple Permissions adds straightforward role and permission management to Filament admin panels. It provides ready-to-use resources and helpers for assigning roles and permissions and restricting access to pages and resources, keeping ACL setup simple for Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by confirming the package even fits your Filament version. It was last released in June 2023 and the repository is archived, so check composer.json constraints against your Filament major before you plan anything around it. If you're on Filament 3+, run composer require z3d0x/filament-simple-permissions in a throwaway branch and let the solver tell you the truth. If it won't resolve, stop here — the rest of this assessment is only useful to you as a design reference.

Assuming it installs:

  1. Install the dependency it rides on. The package layers on top of spatie/laravel-permission. Publish and run Spatie's migrations first, then publish the package config with php artisan vendor:publish --tag="filament-simple-permissions-config".
  2. Read the published config end to end before touching the UI. It's short, and it's the single place where the resource label, navigation group, guard, and permission-model wiring live. Most of the confusion people report with this package traces back to a value in this file.
  3. Register the plugin on one panel only — the admin panel where roles actually belong. Do this inside PanelProvider::panel() and nowhere else.
  4. Clear caches and reload. php artisan filament:optimize-clear then php artisan permission:cache-reset. Open the new Roles entry in the navigation.
  5. First use case — do this before you seed anything real: create a single admin role, tick the permissions you already gate with, assign it to your own user, and walk every page of the panel confirming you can still reach all of it. This is the cheapest possible proof that guard alignment is correct, and guard misalignment is the failure mode you are most likely to hit.

When something is off, look in this order: the package config → Spatie's config/permission.php (guard names and table names must agree) → the package's RoleResource → your own policies. That order resolves the large majority of problems.

Implementation Patterns

Treat permissions as data with one owner. Keep a single source of truth — a PermissionSeeder, an enum, or a config array — and have the package's resource present exactly that set. Scattering 'edit_posts' string literals across policies, Blade, and Filament resource canX() methods is how you accumulate orphaned permissions nobody can safely delete from the UI.

The role screen is administration; policies are enforcement. The UI is a convenience for humans assigning roles. Actual authorization belongs in Laravel policies and Gate calls, and Filament's own authorization flow (canViewAny, canCreate, canDelete, etc.) should be backed by those policies. Don't let the existence of a permissions UI tempt you into thinking the UI is the security boundary.

Guard alignment is the pattern that matters most. Filament panels can define their own auth guard. Decide once whether roles attach to web, to the panel guard, or to both — then set it in the package config and in permission.php and never mix. The classic symptom of getting this wrong is a role that exists, an assignment that exists, and a user who still sees 403s everywhere.

Seed idempotently and deploy through code. Role creation and permission sync belong in a seeder using firstOrCreate plus syncPermissions, run after migrate as part of deploy. Never rely on a human clicking through the Roles screen in production — it's unrepeatable, unauditable, and someone will do it in staging and forget production.

A thin policy per model. The shape that ages best is a small policy mapping each ability to a permission name (view_any_post → canViewAny), plus a narrow Gate::before for a super-admin role. Anything more elaborate tends to duplicate what Filament already asks the policy.

Multi-panel setups: register selectively. Register the plugin only on the panel where role administration belongs. Otherwise every panel — including the customer-facing one — grows a role editor, which is both confusing and a privilege-escalation surface if the wrong person reaches it.

Extend by subclass, not by editing vendor. Adjust label, navigation group, and sort via config. If you genuinely need a new column or action, subclass RoleResource and register your class in place of the default, keeping the file under app/Filament. Edits under vendor/ vanish on the next composer update.

Feature tests: seed the permissions, assert on the ability. Use RefreshDatabase plus your permission seeder, then assert with $user->can('...') rather than driving the UI. For each panel page, cover at least one negative case — a user without the permission gets a 403 — because deny-by-default is the property you actually care about.

Gotchas and Tips

  • Stale permission cache is the #1 false alarm. Spatie caches the permission map. After seeding or creating roles programmatically, run php artisan permission:cache-reset (or call forgetCachedPermissions()) in both tests and deploy scripts. A freshly granted permission that "doesn't work" is nearly always this.
  • config:cache freezes your permission list. Any permission definitions you keep in a config file are baked at cache time. Either re-cache as an explicit deploy step or move the definitions into the database where the seeder can sync them.
  • Guard mismatch looks exactly like a broken package. Before debugging anything else, check guard_name on both the role rows and the permission rows against the guard your panel authenticates with.
  • Seeding order matters on a fresh database. Migrate first, then users, then roles, then assignments. A seeder that touches model_has_roles before Spatie's migration has run fails with an opaque SQL error that reads like a package bug.
  • Beware the broad Gate::before. Returning true from Gate::before short-circuits every policy check, including ones you deliberately locked down. Scope it to a dedicated super-admin role or flag, and write a test proving a non-super-admin is still blocked.
  • Hard-deleting permissions fails silently downstream. Spatie cleans up role assignments, but your policies start denying without warning. Prefer rename-and-deprecate over deletion, and keep the seeder authoritative so removals are deliberate.
  • config:cache + archived package = upgrade risk. Because the repository is archived, treat compatibility as your responsibility. Keep composer.lock committed, pin the version rather than floating, and budget time to fork if a future Filament major leaves you stranded. The codebase is small enough that owning a fork is realistic — verify that before you adopt, not after.
  • Debugging checklist, in order: is the plugin registered on this panel → is the config published and correctly cached → does the guard match → has the permission cache been cleared → does the user pass the resource's own authorization check. Working that list top to bottom resolves most reports in under ten minutes.
  • Don't read release activity as health. The visible history here is Dependabot bumps and CI housekeeping, and the project is now archived. Neither tells you anything about runtime behavior — validate with a spike and an integration test, not with changelogs.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource