hosseinhezami/laravel-permission-manager
Enterprise-grade Laravel permission manager combining RBAC, ABAC, role hierarchy, multi-tenancy, wildcard and temporary permissions, condition engine, multi-guard support, audit logging, middleware DSL, Blade directives, and Gate/Policy integration.
Architecture fit
PermissionTrait on the User model, middleware aliases (pm:permission:*), Blade directives, and Gate::before() hooks. Nothing here fights the framework; it extends the native authorization pipeline rather than replacing it.roles, permissions, permission_groups, permission_sets, role_permissions, role_inherits, user_roles, user_permissions, teams, team_user, permission_conditions, permission_audits, authorization_logs). That is a meaningful commitment of our database namespace and migration graph versus Spatie's ~5 tables.teams + pm.team middleware is opinionated tenancy: it wants to own tenant context resolution (e.g., X-Team-Id header). That will collide with any existing tenancy layer (stancl/tenancy, Spatie multitenancy, or a homegrown tenant_id global scope). This is the single largest architectural integration question.Integration feasibility
composer require → publish config → publish migrations → migrate → add trait. There is also a permission-manager:install --migrate convenience command. A competent Laravel engineer can have a green path in under a day.permission:sync-routes (generate permissions from the route table), resource generator (CRUD permissions per model), import/export (JSON/CSV/YAML), and diagnostic CLI (permission:doctor, permission:why, permission:tree). The explain() API and permission:why are disproportionately valuable for support load — authorization bugs are otherwise expensive to triage.Technical risk
!users.delete) is powerful and easy to misconfigure. Misconfiguration here is a security defect, not a UX defect. explain() mitigates, but requires discipline.* and users.* are one keystroke from privilege escalation. Needs policy, review gates, and CI linting on seeded permission definitions.eval() — good. But it is a bespoke DSL we will be authoring, reviewing, and debugging without a formal spec beyond the README.file or database cache drivers, correctness degrades to staleness.Key questions
X-Team-Id header)?laravel-permission importer, or must we write the ETL?authorization_logs (per-access-attempt logging) is on by default.Stack fit
Migration path
AuthorizationService interface that today delegates to existing code and tomorrow delegates to this package. This makes the dependency reversible and is the single best risk mitigation available, given the maturity profile.composer require hosseinhezami/laravel-permission-manager:1.x.x) and keep a fork-ready posture.Compatibility
web, api, admin isolation) is a genuine differentiator and matches how most apps actually separate staff and customer surfaces.Gate::before() registration is a shared global — confirm no other package or AuthServiceProvider block registers one, or ordering will silently change authorization outcomes.Sequencing
AuthorizationService boundary; forbid direct facade/trait use outside it.explain() usage.Maintenance
composer.lock diff review in CI, a quarterly upstream-health check (open issues, time-to-merge, release cadence validated against Packagist), and a pre-agreed trigger for forking (e.g., two missed Laravel compatibility windows).Support
permission:why, permission:doctor, permission:tree, PermissionSnapshot, and explain() should be documented in our internal runbook before rollout. These convert "user says they can't see the button" from an hour of code archaeology into a one-command answer.Scaling
authorization_logs (optional access-attempt logging) introduces write amplification on the hottest path. Default it off; enable only for targeted debugging or compliance windows with sampling.Failure modes
| Failure | Impact | Mitigation |
|---|---|---|
| Cache driver lacks tag support | Stale or over-permissive grants | Enforce Redis; add a boot-time assertion |
Wildcard * or users.* mis-seeded |
Silent privilege escalation | Lint seeded permissions in CI; ban * outside super-admin |
| Deny/allow precedence misunderstood | Users see or lose access unexpectedly | explain() in support tooling; test matrix per precedence tier |
| Cyclic role inheritance | Runtime exception on check | Catch in seeding; assert hierarchy is a DAG at deploy |
| Missing team context in jobs/console | Cross-tenant leakage or false denials | Require explicit tenant binding; fail closed |
Gate::before() conflict with existing package |
Authorization silently altered | Audit all Gate::before registrations before install |
| Abandoned upstream / no Laravel-N support | Blocked framework upgrade | Fork plan + version pin + quarterly health review |
| Unbounded audit tables | Query and storage degradation | Retention policy, partitioning, archival job |
Ramp-up
TPM recommendation
Conditional adopt. The capability set is genuinely differentiated — ABAC plus multi-tenancy plus hierarchy plus explain() is a real gap in the Laravel ecosystem — and the integration cost is low. But 62 stars and zero dependents mean we are the first production user, and the support model is "we are the support model."
Approve for a greenfield, multi-tenant Laravel product where ABAC is a stated requirement, behind the AuthorizationService wrapper, in a 6–8 week time-boxed pilot with go/no-go gates on: upstream responsiveness, measured check latency under our cache driver, and our team's ability to author conditions without escalation. Decline for brownfield systems already working on Spatie, and hard-decline for any context where an authorization defect requires a vendor SLA.
How can I help you explore Laravel packages today?