PHPackages                             rivalex/clearance - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. rivalex/clearance

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

rivalex/clearance
=================

A complete admin panel (Livewire 4 + Flux UI) for managing permissions, roles, role ceilings and contextual authorization on top of spatie/laravel-permission - installable via a single artisan command, fully opt-in and configurable for exposure to admins or managers.

1.0.2(3w ago)060MITPHPPHP ^8.3CI passing

Since Jul 4Pushed 2w agoCompare

[ Source](https://github.com/rivalex/clearance)[ Packagist](https://packagist.org/packages/rivalex/clearance)[ Docs](https://github.com/rivalex/clearance)[ GitHub Sponsors]()[ RSS](/packages/rivalex-clearance/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (30)Versions (4)Used By (0)

[![Clearance](resources/images/clearance-mark-horizontal.svg)](https://rivalex.github.io/clearance-docs/)---

### **A complete permissions, roles &amp; contextual authorization panel for Laravel**

[](#a-complete-permissions-roles--contextual-authorization-panel-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/eb41f43fa30aae6e7d78534edc920412a99d57fcb6c347d4d0c1735d1581103c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f726976616c65782f636c656172616e63652e737667)](https://packagist.org/packages/rivalex/clearance)[![PHP Version](https://camo.githubusercontent.com/c8d8dad6beb757a2b8acba331d16140813699543b88a37af0a81f20bd35f61de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d626c7565)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/c37a07850aeb86be9be99b0889e65daf261388751c827c12a6fbdc996bfc0d1a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31322d2d31332d6f72616e6765)](https://laravel.com)[![License](https://camo.githubusercontent.com/cc025b5ee2f84b128c51d038d879cfc28cb13ba7a02e33e61e5a4cc993d03ae7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f726976616c65782f636c656172616e6365)](LICENSE.md)[![codecov](https://camo.githubusercontent.com/a77c01da0e7d7ea8e66ac882a57fd357bccdf06c9f21beaa1dd209cfe14e9506/68747470733a2f2f636f6465636f762e696f2f6769746875622f726976616c65782f636c656172616e63652f6272616e63682f6d61737465722f67726170682f62616467652e7376673f746f6b656e3d6f6763394d316e654566)](https://codecov.io/github/rivalex/clearance)[![Tests](https://github.com/rivalex/clearance/actions/workflows/run-tests.yml/badge.svg)](https://github.com/rivalex/clearance/actions/workflows/run-tests.yml)

A drop-in admin panel for Laravel applications built on top of [spatie/laravel-permission](https://github.com/spatie/laravel-permission). Adds a Livewire 4 + Flux UI panel with contextual authorization and role ceilings - installable with one artisan command, without altering any Spatie table.

---

[Official Documentation](https://rivalex.github.io/clearance-docs/)
-------------------------------------------------------------------

[](#official-documentation)

---

What Clearance gives you
------------------------

[](#what-clearance-gives-you)

- **Admin panel** for Permissions, Roles, Guards, Settings and a Dashboard - use the pre-built routes or embed each Livewire component individually.
- **Contextual authorization** - grant a role or permission scoped to a specific model instance (a Store, a Tenant, a Project), with `$user->canIn()`, `@canin`/`@hasrolein` Blade directives, and a `ContextService` for use outside the User model.
- **Ceiling roles** - a role can declare a parent role whose permission set acts as an upper bound; a child role can never exceed its parent, enforced automatically on every save.
- **Fine-grained write permissions** - one delegable `clearance-{section}-write` permission per panel section, so you can hand out "manage roles" without also handing out "manage settings."
- **Super Admin** with an opt-in global Gate bypass, alias detection for existing admin-like roles, and safe non-destructive promotion.
- **Users module** (opt-in) - assign roles globally or to a specific context, plus per-context permission overrides, from a per-user panel.
- **Settings panel** - per-role/guard display name, description, sanitized SVG icon and color; a configurable default role with auto-assign and bulk-assign.
- **Guards management** - database-backed guards, injected into `auth.guards` at boot, restricted to an allow-listed set of drivers.
- **`clearance:install`** - one command sets up Spatie (if missing), migrations, permissions, and the `super_admin` role.
- **`clearance:backfill`** - adopt Clearance into an app that already has Spatie roles/permissions.
- **9 bundled languages** (ar, en, es, fr, hi, it, pt, ru, zh), key-parity tested.
- **Extensibility hooks** - `HasClearance` trait, `HasPermissionGroups` trait, `ClearanceContextable` contract, reusable Blade components.
- **SVG sanitization** - every user-supplied icon passes through an allow-list sanitizer before storage and at render time.
- **Security-hardened** - privilege-escalation ceilings on every permission-granting path, deny-authoritative context overrides, protected `clearance-*` namespace. See [Security](#security).
- **370 tests, 1054 assertions** - Pest suite covering commands, services, Livewire components, contextual authorization, ceiling roles, and i18n key-parity.

Requirements
------------

[](#requirements)

DependencyVersionPHP^8.3Laravel^12.0 | ^13.0spatie/laravel-permission^6.0livewire/livewire^3.0 | ^4.0livewire/flux^2.14Installation
------------

[](#installation)

```
composer require rivalex/clearance
```

Run the installer:

```
php artisan clearance:install
```

> **Always run `clearance:install`, never a plain `php artisan migrate` on a fresh setup.** Clearance's own migrations depend on Spatie's `roles`/`permissions` tables existing first; the installer publishes and runs Spatie's migrations before its own. If you migrate directly and Spatie isn't set up yet, you'll get an actionable error message telling you to run the installer instead.

Optional flags:

FlagDescription`--user=ID`Assign the `super_admin` role to a user after install`--role=NAME`Assign `clearance-access` to a role (created if absent)`--super-admin-role=NAME`Promote an existing role to `super_admin` (skips interactive prompt)`--force`Re-run even if already installedWhat the installer does:

1. Publishes `config/clearance.php`.
2. Publishes Clearance's migrations.
3. Detects Spatie Permission tables - if the `roles` table is absent, publishes and runs Spatie's migrations automatically first.
4. Runs all pending migrations.
5. Creates `clearance-access` and all 5 fine-grained capability permissions: `clearance-permissions-write`, `clearance-roles-write`, `clearance-guards-write`, `clearance-settings-write`, `clearance-users-write`.
6. Creates the `super_admin` role with all `clearance-*` permissions assigned (additive - never removes existing permissions on re-run).
7. Writes `storage/.clearance-installed` as an idempotency marker.

> **Migrating from an existing Spatie install?** Use `php artisan clearance:backfill` (see [Migrating from an existing Spatie install](#migrating-from-an-existing-spatie-install)) and read [docs/migration-from-spatie.md](docs/migration-from-spatie.md) first - important notes on `super_admin` collision, custom model subclasses, and guard import.

---

⚠️ Required: add `HasClearance` to your User model
--------------------------------------------------

[](#️-required-add-hasclearance-to-your-user-model)

To use contextual authorization methods (`$user->canIn()`, `$user->hasRoleIn()`), add the `HasClearance` trait to `App\Models\User`. It already includes Spatie's `HasRoles` - **one line replaces both**:

```
use Rivalex\Clearance\Traits\HasClearance;

class User extends Authenticatable
{
    use HasClearance; // includes HasRoles + all contextual authorization methods
}
```

> **Already using `use HasRoles`?** Replace it with `use HasClearance`, or keep both - PHP deduplicates trait composition automatically, no conflicts.

Without this trait, `$user->canIn()` and related methods are unavailable, but the Blade directives (`@canin`, `@hasrolein`) and `ContextService` keep working regardless (they don't depend on the trait).

---

Quick Start
-----------

[](#quick-start)

### Option A - Pre-built routes

[](#option-a---pre-built-routes)

After installation the panel is available at `/clearance` (or the configured `route_prefix`). All routes are protected by the `clearance.access` middleware and use the host app's Livewire layout automatically.

URIRoute nameDescription`/clearance``clearance.home`Dashboard`/clearance/guards``clearance.guards`Guard management (create/edit/delete)`/clearance/permissions``clearance.permissions`Permission CRUD with group-prefix naming validation`/clearance/roles``clearance.roles`Role CRUD with guard-scoped permission assignment, scope (global/contextual), and ceiling`/clearance/settings``clearance.settings`Display metadata (icons, colors), default role, general settings`/clearance/user/{userId}``clearance.user`Per-user role assignment + contextual permission overrides (requires `modules.users = true`)Route names stay stable regardless of prefix changes. To customize middleware:

```
// config/clearance.php
'middleware' => ['web', 'auth', 'verified'],
```

### Option B - Embedded Livewire components

[](#option-b---embedded-livewire-components)

Each panel section can be mounted individually inside any Blade view, Filament page, or custom route:

```

{{-- Users module (requires modules.users = true in config) --}}

```

---

Contextual Authorization
------------------------

[](#contextual-authorization)

Clearance extends Spatie's global authorization model with **context-scoped** checks. A user's roles can be assigned within a specific context (e.g. a Store, Tenant, or Project) and are invisible outside that scope.

### On the User model

[](#on-the-user-model)

```
// Does the user have this permission in this context?
$user->canIn('orders-create', $store);

// Alias - mirrors Spatie's hasPermissionTo() naming
$user->hasPermissionIn('orders-create', $store);

// Does the user hold this role in this context?
$user->hasRoleIn('manager', $store);

// Optionally filter by guard
$user->canIn('orders-create', $store, 'api');
$user->hasRoleIn('manager', $store, 'web');
```

### In Blade views

[](#in-blade-views)

```
@canin('orders-create', $store)
    New Order
@endcanin

@hasrolein('manager', $store)
    Reports
@endhasrolein
```

Both directives resolve safely (return `false`) for a guest user - they never throw.

### Via ContextService (advanced)

[](#via-contextservice-advanced)

For use in controllers, policies, or jobs where the User model may not have the trait:

```
use Rivalex\Clearance\Services\ContextService;

$service = app(ContextService::class);

$service->canIn($user, 'orders-create', $store);
$service->hasPermissionIn($user, 'orders-create', $store); // alias
$service->hasRoleIn($user, 'manager', $store);
$service->resolveFor($user, $store); // Collection of all effective permission names
```

Or via the `Clearance` facade, which delegates to the same service:

```
Clearance::canIn($user, 'orders-create', $store);
Clearance::resolveFor($user, $store);
Clearance::guards(); // names of all managed authentication guards
```

### How resolution works

[](#how-resolution-works)

`resolveFor()` merges three sources, in this precedence order:

1. **Contextual role grants** - permissions from roles the user holds specifically within this context (`clr_role_ctx`).
2. **Global role grants** - permissions from the user's globally-assigned Spatie roles (so `super_admin` and other global roles satisfy `canIn()` for any context).
3. **Per-context overrides** (`clr_ctx_overrides`) - `forced_on` adds a permission on top of the above; `forced_off` **removes it, even if the permission was granted by a global role**. A deny always wins.

---

Super Admin
-----------

[](#super-admin)

The `super_admin` role is created automatically by `clearance:install` and kept in sync with all `clearance-*` permissions.

```
# Install and make user ID 1 a super admin
php artisan clearance:install --user=1
```

### Gate bypass (opt-in)

[](#gate-bypass-opt-in)

`super_admin_gate_bypass` controls whether the `super_admin` role bypasses **all** Laravel `can()` / `Gate::allows()` / policy checks globally, via a `Gate::before()` hook.

> **Default: `false`.** The bypass is opt-in. To enable it:

```
// config/clearance.php
'super_admin_gate_bypass' => true,
```

When enabled, any user holding `super_admin` skips all Gate checks **application-wide** - not only Clearance panel checks. For a narrower scope, leave it off and grant permissions explicitly.

### Alias detection

[](#alias-detection)

If your database already contains a role named `super_admin`, `superadmin`, `super-admin`, `root`, or `owner`, the installer detects it and prompts you interactively to promote it or create a separate `super_admin`. Use `--super-admin-role=NAME` to skip the prompt:

```
php artisan clearance:install --super-admin-role=owner
```

Promotion renames the role in place - all existing `model_has_roles` assignments are preserved via the FK on `role_id`.

---

Panel Access &amp; Fine-grained write permissions
-------------------------------------------------

[](#panel-access--fine-grained-write-permissions)

Navigate to `/clearance` after installation. Read access to the whole panel requires the `clearance-access` permission (checked via `can()`, never `hasRole()`):

```
$user->givePermissionTo('clearance-access');
```

Write operations on each section are gated by a dedicated, delegable permission - all created by `clearance:install` and assigned to `super_admin`:

PermissionControls`clearance-permissions-write`Create / edit / delete permissions`clearance-roles-write`Create / edit / delete roles and their permission assignments`clearance-guards-write`Create / edit / delete guards`clearance-settings-write`Edit display metadata, icons, colors, default role`clearance-users-write`Assign / remove roles for a specific user```
// Grant a user write access to roles only:
$user->givePermissionTo('clearance-access');
$user->givePermissionTo('clearance-roles-write');
```

If a fine-grained permission row doesn't exist at all in the database (a legacy pre-seeding state), the check falls back to `clearance-access` for backwards compatibility. On any instance that has run `clearance:install`, this fallback never activates.

`clearance-*` permissions are reserved: they cannot be created, renamed, deleted, or added to any role except through the package's own install flow - even by a `super_admin` actor for the `super_admin` role itself.

---

Roles
-----

[](#roles)

### Scope: global vs. contextual

[](#scope-global-vs-contextual)

Every role declares a scope at creation time:

- **`global`** - assigned directly to a user via `$user->assignRole()`, applies everywhere.
- **`contextual`** - bound to one or more model types (`context_types`), assignable only within a specific context instance via `UserRoleContext`.

Roles without an explicit `RoleMeta` row default to `global` for backwards compatibility.

### Ceiling roles

[](#ceiling-roles)

A role can declare a **ceiling** - a parent role whose permission set acts as an upper bound:

```
use Rivalex\Clearance\Services\RoleService;

app(RoleService::class)->setParent($childRole, $parentRole);
```

- The child can only ever hold permissions the parent also holds. Any excess is **silently trimmed** on `setParent()` and on every subsequent permission sync - no exception, no error message, just enforced silently.
- A role that already acts as a parent cannot become a child (`ClearanceScopeViolationException`).
- A role that is already a child cannot itself act as a parent (`ClearanceScopeViolationException`).
- Removing permissions from a parent cascades the removal to every child automatically.
- Setting a permissive parent grants the child nothing by itself - the ceiling only **trims**, it never **grants**.

This is configured per-role in the Roles panel (`RoleForm`), or programmatically via `RoleService::setParent()` / `removeParent()`.

---

Guards
------

[](#guards)

Guards can be managed from the panel and are injected into `auth.guards` at application boot, so they're recognized by Laravel's auth system before any request runs. Only drivers in the allow-list are accepted:

```
// config/clearance.php
'allowed_guard_drivers' => ['session', 'token', 'jwt', 'passport', 'sanctum'],
```

A guard with an unlisted driver is skipped at boot (with a log warning) rather than corrupting the auth config.

---

Users module (opt-in)
---------------------

[](#users-module-opt-in)

Disabled by default. Enable it in `config/clearance.php`:

```
'modules' => ['users' => true],
```

Navigate to `/clearance/user/{userId}` to manage a specific user's roles and permissions. Access requires `clearance-access` (read) and `clearance-users-write` (assign/remove).

### What the panel does

[](#what-the-panel-does)

- **Global role assignment** - assign `scope=global` roles directly to the user, application-wide.
- **Contextual role assignment** - assign `scope=contextual` roles scoped to a specific model instance (a Store, Team, or Project declared in `contextual_models`).
- **Per-context permission overrides** - for each contextual role assignment, additional permissions can be force-granted or force-denied independently per context instance.
- **Remove assignment** - removes a role from the user (global or contextual scope), cascading the deletion of any associated overrides.

Both role assignment and direct/override permission grants enforce a privilege ceiling: a non-`super_admin` actor cannot modify their own assignments, and cannot grant a permission they don't themselves hold.

### Linking to the panel from your app

[](#linking-to-the-panel-from-your-app)

```
route('clearance.user', ['userId' => $user->id])
```

### Contextual roles under the hood

[](#contextual-roles-under-the-hood)

```
use Rivalex\Clearance\Models\UserRoleContext;

// Samuele is "StoreStaff" only within Alessandro's Store
UserRoleContext::create([
    'user_id'      => $samuele->id,
    'role_id'      => $staffRole->id,
    'context_type' => Store::class,
    'context_id'   => $store->id,
]);
```

Authorization checks respect the context via `$user->canIn()`, `@canin`, and `ContextService`.

---

Settings
--------

[](#settings)

The Settings panel (`clearance-settings-write` to edit) lets you configure:

- **Display metadata** per role/guard - display name, description, and a sanitized SVG icon + hex color, shown throughout the panel.
- **Default role** - the role automatically assigned to newly registered users when `auto_assign_default_role` is `true`.
- **Bulk-assign default role** - one-click assignment of the current default role to every existing user who doesn't already have it.
- **Show icons** - toggles icon display across the panel.

```
// config/clearance.php
'auto_assign_default_role' => true, // requires a default role set in Settings
```

---

Dashboard
---------

[](#dashboard)

The Dashboard shows at-a-glance stats: total roles, guards, and permissions; the number of distinct permission groups (by naming prefix); the number of contextual role assignments; and the top 5 roles ranked by user count.

---

Permission Naming Convention
----------------------------

[](#permission-naming-convention)

Permissions must follow the `group-action` format:

```
orders-create       ✓
orders-read         ✓
store-orders-delete ✓

create              ✗  (bare action, no group)
orders.create       ✗  (dot separator)
Orders-Create       ✗  (camelCase)

```

Disable enforcement per environment:

```
'enforce_naming_convention' => false,
```

The separator itself (`-` or `_`) is validated at boot - it's the only piece of this config that reaches a raw SQL fragment (grouping/sorting permissions), so only those two characters are accepted.

---

Configuration
-------------

[](#configuration)

Publish the config:

```
php artisan vendor:publish --tag=clearance-config
```

`config/clearance.php` reference:

KeyDefaultPurpose`route_prefix``'clearance'`URI prefix for all panel routes.`middleware``['web', 'auth']`Applied to all panel routes before `clearance.access`.`access_permission``'clearance-access'`Permission checked by the access middleware.`user_model``null`Defaults to `auth.providers.users.model`.`modules.users``false`Master switch for the Users module (routes + Livewire components).`contextual_models``[]``FQCN => ['label', 'icon', 'label_attribute', 'searchable']` - models that can act as role-binding contexts.`enforce_naming_convention``true`Enforce `group-action` permission naming.`naming_separator``'-'`Separator character - `'-'` or `'_'` only.`guards``[]`Override auto-detected guards from `config/auth.php`. Empty = auto-detect all.`allowed_guard_drivers``['session', 'token', 'jwt', 'passport', 'sanctum']`Drivers accepted when injecting DB guards into `auth.guards`.`layout``null`Blade layout for full-page components. `null` = host app's default (`config('livewire.component_layout')`).`auto_assign_default_role``false`Auto-assign the Settings-configured default role on `Registered` event.`super_admin_gate_bypass``false`Opt-in: `super_admin` bypasses all Gate checks application-wide.`ui.flux_pro``null``null` = auto-detect via `Flux::pro()`.`dark_mode.force``env('CLEARANCE_FORCE_DARK_MODE', false)`Always render Clearance's dark theme regardless of the host app or OS color scheme. Overridable live from the Settings UI (Appearance card), which takes precedence over this default.---

Appearance
----------

[](#appearance)

Clearance's own CSS uses a class-based `dark:` variant (`&:where(.dark, .dark *)`), so it normally follows the host app's `` ancestor - the same convention as Tailwind's default class strategy. If your host app has no class-based dark toggle (or its state doesn't match the real OS/browser preference), Clearance's own styling can render unstyled even though the rest of the page looks fine.

```
// config/clearance.php
'dark_mode' => [
    'force' => env('CLEARANCE_FORCE_DARK_MODE', false),
],
```

Set `force` to `true` (or `CLEARANCE_FORCE_DARK_MODE=true`) to always render Clearance's dark theme, regardless of the host app or OS color scheme - useful when embedding Clearance in a host with no dark-mode toggle, or while developing locally on a light-mode system. Can also be toggled live from the Appearance card in `/clearance/settings`, which takes precedence over this config default.

---

Database
--------

[](#database)

Clearance owns 6 tables and never alters Spatie's core tables (`roles`, `permissions`, `model_has_roles`, `model_has_permissions`, `role_has_permissions`). All FKs referencing `roles.id`/`permissions.id` cascade on delete unless noted; Spatie tables have no FKs pointing back to `clr_*`.

TableKey columns`clr_meta``subject_type`, `subject_key` (unique together) · `display_name`, `description`, `icon_svg`, `color` - display metadata for a role or guard`clr_role_meta``role_id` (unique, FK → `roles`) · `is_locked`, `scope` (`global`|`contextual`), `context_types` (json) · `parent_role_id` (nullable FK → `roles`, `ON DELETE SET NULL`) - ceiling role`clr_guards``name` (unique), `driver`, `provider` - guards managed via the panel`clr_settings``key` (unique), `value` - runtime key/value store (default role, etc.)`clr_role_ctx``user_id`, `role_id` (FK → `roles`), `context_type`, `context_id` - contextual role assignments, unique per `(user, role, context_type, context_id)``clr_ctx_overrides``user_id`, `role_id` (FK → `roles`), `permission_id` (FK → `permissions`), `context_type`, `context_id`, `type` (`forced_on`|`forced_off`) - per-user, per-context permission overrides---

Extending the package
---------------------

[](#extending-the-package)

- **`HasClearance` trait** (`Rivalex\Clearance\Traits\HasClearance`) - adds `canIn()`, `hasPermissionIn()`, `hasRoleIn()` to your User model; includes Spatie's `HasRoles`.
- **`HasPermissionGroups` trait** (`Rivalex\Clearance\Concerns\HasPermissionGroups`) - if you configure a custom `Permission` model (`config('permission.models.permission')`) instead of Clearance's own, add this trait to keep the grouped-UI accessors (`permission_group`, `group_string`, `abilities()`, `colorForAbility()`) working:

```
use Rivalex\Clearance\Concerns\HasPermissionGroups;

class Permission extends \Spatie\Permission\Models\Permission
{
    use HasPermissionGroups;
}
```

- **`ClearanceContextable` contract** (`Rivalex\Clearance\Contracts\ClearanceContextable`) - implement `clearanceLabel(): string` on a context model for a custom display label in the panel; otherwise `contextual_models..label_attribute` (default `name`) is used.
- **Reusable Blade components** - registered under the `clearance::` namespace, usable in your own views: `x-clearance::message`, `x-clearance::clipboard`, `x-clearance::validation-errors`, plus a small icon set (`x-clearance::icon.*`). No external JS dependency beyond Alpine (already required by Livewire).

---

i18n
----

[](#i18n)

9 languages ship out of the box: `ar`, `en`, `es`, `fr`, `hi`, `it`, `pt`, `ru`, `zh` (`resources/lang/{locale}/ui.php`). All locales expose an identical key set, verified by a dedicated test on every change.

To add or override a language, publish the translation files:

```
php artisan vendor:publish --tag=clearance-translations
```

This copies them to `lang/vendor/clearance/{locale}/ui.php` in your app. Add a new locale directory there, using `en/ui.php` as the canonical key reference.

---

Migrating from an existing Spatie install
-----------------------------------------

[](#migrating-from-an-existing-spatie-install)

If your application already uses `spatie/laravel-permission` with existing roles, permissions, and assignments, `clearance:install` detects and preserves them - it never runs Spatie's migrations if the `roles` table already exists.

Backfill Clearance-specific metadata for pre-existing Spatie data:

```
php artisan clearance:backfill              # meta + role scope + guards
php artisan clearance:backfill --only=meta  # just one section
php artisan clearance:backfill --dry-run    # preview, no writes
```

- `meta` - seeds a `clr_meta` display name (title-cased role name) for every role without one.
- `roles` - seeds `clr_role_meta` defaults (`scope=global`, `is_locked=false`) for every role without one.
- `guards` - imports guards from `config('auth.guards')` into `clr_guards`, filtered by `allowed_guard_drivers`.

All sections are idempotent. Full guide, including `super_admin` collision handling and custom model subclass notes: [docs/migration-from-spatie.md](docs/migration-from-spatie.md).

---

Security
--------

[](#security)

Clearance went through a dedicated pre-publication security audit plus two follow-up hardening passes before this release. Highlights: privilege-escalation ceilings on every permission-granting path (direct grants and role-level syncing alike), deny-authoritative context overrides, an allow-list SVG sanitizer, a protected `clearance-*` permission namespace, and guest-safe Blade directives.

Full audit trail, findings, and fixes: [`docs/plans/security-audit/plan.md`](docs/plans/security-audit/plan.md).

Found a vulnerability? Please report it privately to the maintainer rather than opening a public issue.

---

Tips &amp; Gotchas
------------------

[](#tips--gotchas)

- **Always run `clearance:install`**, not a plain `migrate`, on a fresh setup - Clearance's migrations depend on Spatie's tables existing first.
- **Add `HasClearance` to your User model** to unlock `$user->canIn()`/`hasRoleIn()`; the Blade directives and `ContextService` work without it.
- **`forced_off` always wins** - even over a permission granted by a global role. Use it deliberately.
- **A ceiling role only trims, never grants.** Setting a permissive parent role doesn't hand the child anything on its own - the child still needs those permissions explicitly assigned.
- **The Gate bypass is application-wide, not panel-scoped.** Turning on `super_admin_gate_bypass` affects every `can()`/`Gate::allows()`/policy check in your app.
- **The Users module is off by default.** Set `modules.users => true` to expose it.
- **`clearance-*` permissions are untouchable outside the install flow** - by design, so the panel's own access control can't be tampered with from inside the panel.

Testing
-------

[](#testing)

370 tests, 1054 assertions - covering commands, services, Livewire components, contextual authorization, ceiling roles, and i18n key-parity across all 9 bundled languages.

```
vendor/bin/pest
vendor/bin/pest --coverage
```

License
-------

[](#license)

MIT - see [LICENSE.md](LICENSE.md).

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance97

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 70.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Total

3

Last Release

24d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b5c3130d9237407ef79b7512e965bf56275c61a1930739113046af35f580f539?d=identicon)[rivalex](/maintainers/rivalex)

---

Top Contributors

[![rivalex](https://avatars.githubusercontent.com/u/580591?v=4)](https://github.com/rivalex "rivalex (51 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (13 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (8 commits)")

---

Tags

access-controlacladmin-panelauthorizationflux-uilaravellaravel-packagelivewirelivewire-4permissionsphpphp8rbacrolesspatie-permissionspatielaravelauthorizationfluxlivewireaclrolespermissionsrbacadmin-panel

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/rivalex-clearance/health.svg)

```
[![Health](https://phpackages.com/badges/rivalex-clearance/health.svg)](https://phpackages.com/packages/rivalex-clearance)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

13.0k107.5M1.6k](/packages/spatie-laravel-permission)[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k4.3M163](/packages/bezhansalleh-filament-shield)[filament/support

Core helper methods and foundation code for all Filament packages.

2333.9M302](/packages/filament-support)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3915.5k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
