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

Nova Permission Laravel Package

kiritokatklian/nova-permission

A Laravel Nova tool for managing roles and permissions with Spatie's laravel-permission package. It adds a clean Nova UI to create roles, assign permissions, and attach roles to users, simplifying authorization management in Nova admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a Nova tool + resource set for spatie/laravel-permission. It gives you UI to create roles/permissions and fields to attach them to your models.

  1. Install the dependency (the fork exists mainly to track newer Nova/spatie versions, so pin both). As of 5.3.0 the package now declares support for spatie/laravel-permission v8 — the first release in the 5.x line to do so:

    composer require kiritokatklian/nova-permission:^5.3 spatie/laravel-permission:^8.0
    

    Confirm in composer.json / composer why spatie/laravel-permission that the resolved constraint matches your Nova major. If you are still on spatie v6/v7, you can stay on a pre-5.3 package release — but the two must move together, and composer update will happily pick 5.3.0 the moment you bump spatie, so check what actually resolved rather than what you typed.

  2. Ensure spatie/laravel-permission is migrated (if not already):

    php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
    php artisan migrate
    

    On the spatie v7 → v8 jump, re-publish and diff the config file rather than assuming your old one is still valid, then php artisan config:clear.

  3. Register the tool in app/Providers/NovaServiceProvider.php:

    public function tools(): array
    {
        return [
            new \Kiritokatklian\NovaPermission\NovaPermissionTool(),
        ];
    }
    
  4. Expose the bundled resources (Nova auto-discovers app/Nova, not vendor resources):

    protected function resources(): void
    {
        Nova::resources([
            \Kiritokatklian\NovaPermission\Role::class,
            \Kiritokatklian\NovaPermission\Permission::class,
        ]);
    }
    
  5. Where to look first: the tool class (NovaPermissionTool) for static config hooks, then the Role / Permission resources, then the field classes (RoleBooleanGroup, PermissionBooleanGroup, and the select variants). Read the source—it's small and the README lags behind the code.

First use case: log in as a super-admin, open the Permissions menu, create permissions (posts.view, posts.publish), create a role, tick permissions on it, then add RoleBooleanGroup::make('Roles') to your User resource and assign the role. That end-to-end loop is the whole point of the package.

Implementation Patterns

Assign roles to users with the BooleanGroup field:

use Kiritokatklian\NovaPermission\RoleBooleanGroup;

RoleBooleanGroup::make('Roles')
    ->hideFromIndex()
    ->help('Roles drive what this user can do in the app.'),

Attach permissions to roles — the bundled Role resource already includes this, but for a custom Role resource:

PermissionBooleanGroup::make('Permissions')
    ->options(fn () => \Spatie\Permission\Models\Permission::pluck('name', 'id'))
    ->hideFromIndex(),

Extend rather than replace the bundled resources. Create App\Nova\Role extends \Kiritokatklian\NovaPermission\Role, add fields (description, tenant, color), then register your class instead of the vendor one. Same for Permission. This keeps upgrades cheap.

Use the select fields for filtering/reporting. RoleSelect / PermissionSelect are thin wrappers that populate options from the spatie tables—handy on User index filters or on unrelated resources that need to reference a role.

Gate visibility centrally:

// NovaServiceProvider::tools()
new \Kiritokatklian\NovaPermission\NovaPermissionTool()

and restrict via NovaPermissionTool::canSee(...) (or wrap in Gate::allows) so only admins see the menu entry.

Keep the UI as a convenience layer, not the source of truth. Seed canonical permissions and role definitions in a seeder:

foreach (['posts.view', 'posts.publish', 'users.manage'] as $name) {
    Permission::findOrCreate($name, 'web');
}
$editor = Role::findOrCreate('editor', 'web');
$editor->syncPermissions(['posts.view', 'posts.publish']);

UI edits then layer on top for ad-hoc changes; code stays reproducible across environments.

Super-admin bypass belongs in AuthServiceProvider, not in the package:

Gate::before(fn ($user, $ability) => $user->hasRole('super-admin') ? true : null);

Upgrade spatie and this package as one unit. When moving to spatie v8, the sequence that works: bump both constraints in composer.json, composer update kiritokatklian/nova-permission spatie/laravel-permission, run any new spatie migrations, php artisan config:clear, then php artisan permission:cache-reset. Only after that do you re-check the Nova UI — that way a broken authorization check is attributable to one change, not two.

Gotchas and Tips

  • Authorization is not included. Nova evaluates viewAny/update against policies for the Role and Permission resources. With no policy, the menu and resources are effectively invisible. Register policies (or a Gate::before) before you assume the install is broken.
  • Permission cache. spatie caches the permission map. Model saves through Nova invalidate it, but bulk DB::table() updates, raw seeders, or Octane workers won't. When in doubt: php artisan permission:cache-reset, or app(PermissionRegistrar::class)->forgetCachedPermissions() after bulk writes. This bites hardest immediately after the v8 upgrade, when stale cached state from the old version is still in your worker/Redis cache.
  • guard_name mismatch is the #1 silent failure. A role on guard web cannot be assigned to a user whose guard is api, and a permission created under the wrong guard simply won't match can(). Multi-guard apps should scope the resources (or add a guard_name field + filter) rather than mixing everything in one list. The guard default comes from spatie's config/permission.php, so any change to that config during a major upgrade silently re-homes permissions created afterwards.
  • Large permission sets break the BooleanGroup UX. A checkbox group with 150 permissions is unusable and slow. Group by domain prefix (e.g., separate fields per module, or a custom relation field) before the list grows.
  • The fork's namespaces differ from spatie/nova-permission. If you're migrating, update import paths (Spatie\NovaPermission\* → Kiritokatklian\NovaPermission\*) in resources, fields, and any class strings in config. Grep for the old namespace rather than trusting the IDE.
  • Teams / tenant-scoped permissions are not handled. spatie's teams feature requires a team context on every check; the package's global UI doesn't know about it. Handle team assignment in your own resource or a custom field, and keep the tool restricted to global admins. Teams behaviour has shifted across spatie majors — re-verify it against v8's docs rather than your memory of v7.
  • Extend via the tool's static config (NovaPermissionTool::resources([...]), policy/canSee hooks) instead of overriding service providers. The exact method names drift between releases—verify against the source for your pinned version.
  • Testing: use RefreshDatabase with a permission seeder; call app(PermissionRegistrar::class)->forgetCachedPermissions() in setUp() so authorization assertions don't inherit a stale cache between tests. Run the suite once against spatie v8 specifically before shipping the bump — a green suite on v7 proves nothing about v8.
  • Version matrix is now wider, not simpler. 5.3.0 widens compatibility (Nova majors × spatie v6/v7/v8) which means "latest of everything" is not automatically a tested combination. Lock both packages in composer.json, and if you hit an odd authorization failure after a routine composer update, the first thing to check is which spatie major you actually resolved to.
  • Upgrading: this package's value is Nova/spatie compatibility, but it's a low-star fork (79 stars) with no dependents and a single maintainer merging community PRs — the 5.3.0 release came in via an outside contributor. Lock the version, review the changelog, and have a fallback (a custom Nova resource over spatie models, ~200 lines) if it stalls before the next spatie major.
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