laravel-permission-audit maintained by tamas1979
Laravel Permission Audit
A simple and reusable Laravel package for Spatie permission/role audit trails and capability blocks.
This package records who granted or revoked a permission or role, when, and why, and can block re-apply of a revoked capability until an admin lifts the block.
It works alongside spatie/laravel-permission — it does not replace it.
It is not a general activity log. Use it when you need audit + block semantics for Spatie abilities.
Features
- Audit trail: append-only history of grant / revoke / assign / remove / block / unblock
- Capability blocks: prevent re-grant via the Auditor API while a block is active
- Spatie event logging: optional listeners write audits for direct Spatie calls
- Facade + service:
PermissionAuditfacade or injectPermissionAuditor - Lightweight: minimal setup, depends only on Laravel + Spatie Permission
Installation
Require the package via Composer (and Spatie Permission if you do not have it yet):
composer require tamas1979/laravel-permission-audit
Configuration
Publish the config file:
php artisan vendor:publish --provider="Tamas1979\PermissionAudit\PermissionAuditServiceProvider" --tag=permission-audit-config
The default config:
return [
'tables' => [
'audits' => 'permission_audits',
'blocks' => 'permission_blocks',
],
// Log direct Spatie givePermissionTo / assignRole / etc.
'listen_spatie_events' => true,
// Callable that returns the actor model (or null). Default: auth()->user()
'actor_resolver' => null,
// PermissionAuditor::grant* refuses when an active block exists
'enforce_blocks_on_grant' => true,
];
Setup
- Run migrations
The package ships migrations for permission_audits and permission_blocks.
Just run:
php artisan migrate
- Migrations load automatically from the package
- Publish them only if you need to customize:
php artisan vendor:publish --provider="Tamas1979\PermissionAudit\PermissionAuditServiceProvider" --tag=permission-audit-migrations
- Spatie Permission
Your user (or other subject) model must already use Spatie’s HasRoles (or equivalent). This package calls Spatie’s grant/revoke APIs under the hood.
For automatic event logging of direct Spatie calls (givePermissionTo, assignRole, …), Spatie 8+ also needs events turned on in config/permission.php:
'events_enabled' => true,
Without this, listen_spatie_events has nothing to listen to — Spatie does not dispatch attach/detach events by default.
Usage
Grant / revoke (preferred API)
use Tamas1979\PermissionAudit\Facades\PermissionAudit;
use Tamas1979\PermissionAudit\AbilityType;
// Grant with reason (audited; refuses if an active block exists)
PermissionAudit::grantPermission($user, 'products.create', reason: 'Accepted creator terms');
// Revoke and block automatic re-apply
PermissionAudit::revokePermission(
$user,
'products.create',
reason: 'Repeated bad product data',
blockReapply: true,
);
// Check before your own onboarding / self-service flow
if (PermissionAudit::isPermissionBlocked($user, 'products.create')) {
// show “suspended — contact support”
}
// Admin lifts the block
PermissionAudit::unblock(
$user,
AbilityType::PERMISSION,
'products.create',
reason: 'Appeal accepted',
);
Roles work the same way:
PermissionAudit::assignRole($user, 'moderator', reason: 'Promoted by admin');
PermissionAudit::removeRole($user, 'moderator', reason: 'Demoted', blockReapply: false);
Automatic Spatie event logging
When listen_spatie_events is true (default) and Spatie’s permission.events_enabled is true, direct calls such as $user->givePermissionTo(...) / assignRole(...) are also written to permission_audits with source = spatie_event.
Spatie 8+ ships with events_enabled => false. Set it to true or the listener will never run.
Auditor methods silence that listener so you do not get duplicate rows.
Important: blocks vs direct Spatie
| Path | Audited? | Block enforced? |
|---|---|---|
PermissionAudit::grantPermission(...) |
yes (source = auditor) |
yes (if enforce_blocks_on_grant) |
$user->givePermissionTo(...) |
yes (if listeners on) | no — bypasses Auditor |
Use the Auditor API for any flow where blocks must stick. Gate or wrap direct Spatie calls yourself if you need hard enforcement everywhere.
Tables
| Table | Purpose |
|---|---|
permission_audits |
Append-only history |
permission_blocks |
Active / lifted blocks |
Contribution
- Open for ideas, bug fixes, and feature requests
- Supports Laravel 11, 12, and 13
- Requires PHP 8.2+ and
spatie/laravel-permission6+
License
MIT