rembon / laravel-auditor
Request-level audit trail for Laravel: who did what, what changed, and what they were allowed to do.
Requires
- php: ^8.3
- illuminate/auth: ^12.0|^13.0
- illuminate/console: ^12.0|^13.0
- illuminate/contracts: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/log: ^12.0|^13.0
- illuminate/queue: ^12.0|^13.0
- illuminate/routing: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- illuminate/view: ^12.0|^13.0
Requires (Dev)
- driftingly/rector-laravel: ^2.0
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-browser: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- rector/rector: ^2.0
Suggests
- rembon/laravel-auditor-filament: Filament panel for browsing audit entries
- rembon/laravel-auditor-pulse: Laravel Pulse cards for audit activity
Provides
None
Conflicts
None
Replaces
None
README
Request-level audit trail for Laravel — who did what, what changed, and what they were allowed to do. Production-safe and compliance-ready.
Why Laravel Auditor?
Every HTTP request, queued job and artisan command becomes one entry: the user, the route, the status, the abilities that were checked (granted or denied), the records that were read, the mails and notifications that went out — and a diff of every model it changed.
| Laravel Auditor v3 | spatie/laravel-activitylog | owen-it/laravel-auditing | Laravel Telescope | |
|---|---|---|---|---|
| Unit of recording | Request / job / command | Manual event / model | Model event | Debug entry |
| Model change diff | ✅ | ✅ | ✅ | ⚠️ (debug) |
| Models read (read audit) | ✅ | ❌ | ⚠️ (retrieved) | ⚠️ |
| Abilities checked (granted/denied) | ✅ | ❌ | ❌ | ✅ (debug) |
| Mail & notifications sent | ✅ (no body) | ❌ | ❌ | ✅ (debug) |
| Correlation request → queued job | ✅ | ❌ | ❌ | ⚠️ (batch id) |
| Tamper-evident (hash chain) | ✅ | ❌ | ❌ | ❌ |
| Built for production | ✅ | ✅ | ✅ | ⚠️ (not recommended) |
Installation
composer require rembon/laravel-auditor php artisan auditor:install
auditor:install publishes the config and migrations, offers to migrate, and prints the
snippets below. Add --integrity to enable the hash chain.
Quick start
Record the changes of a model:
use Rembon\LaravelAuditor\Traits\Auditable; class Post extends Model { use Auditable; // Optional protected array $auditExclude = ['view_count']; protected array $auditEvents = ['updated', 'deleted']; protected bool $auditRetrieved = false; }
Allow access to the dashboard outside local (it is closed by default):
// AppServiceProvider::boot() Gate::define('viewAuditor', fn (User $user) => $user->is_admin);
Schedule the maintenance commands:
// routes/console.php Schedule::command('auditor:prune')->daily(); Schedule::command('auditor:seal')->everyMinute()->withoutOverlapping(); // with integrity Schedule::command('auditor:verify')->daily(); // with integrity
Then open /auditor.
Usage
use Rembon\LaravelAuditor\Facades\Auditor; // Enrich the current entry Auditor::withProperty('order_id', $order->id); Auditor::withProperties(['channel' => 'mobile']); Auditor::tag('checkout', 'payment'); // Control recording Auditor::ignore(); // drop this entry (model changes are kept) Auditor::withoutAuditing(fn () => $post->save()); // nothing inside is recorded Auditor::correlationId(); // shared with the jobs it dispatches // Customise (in a service provider) Auditor::auth(fn (Request $request) => $request->user()?->isAdmin()); Auditor::resolveUserUsing(fn () => auth('admin')->user()); Auditor::filter(fn (EntryData $entry) => $entry->name !== 'health.check'); Auditor::redactUsing(fn (string $key, mixed $value) => $key === 'nik'); Auditor::extend('s3', fn (Application $app) => new S3Storage(/* ... */)); Auditor::displayUserUsing(fn ($user) => ['name' => $user->name, 'avatar' => $user->avatar_url]);
Query the trail:
$post->audits; // newest first ModelChange::query()->causedBy($user)->since(now()->subWeek())->get(); Entry::query()->forCorrelation($id)->get(); // request + its jobs Entry::query()->withDeniedAbilities()->get();
Testing your application
Auditor::fake(); $this->actingAs($user)->put("/posts/{$post->id}", ['title' => 'New']); Auditor::assertChangeRecorded(Post::class, $post->id, ChangeEvent::Updated, fn (ModelChangeData $change) => $change->newValues['title'] === 'New'); Auditor::assertEntryRecorded(fn (EntryData $e) => $e->userId === (string) $user->id); Auditor::assertAbilityDenied('delete-post'); Auditor::assertNothingRecorded();
Privacy & safety defaults
- Keys such as
password,*token*,*secret*,authorization, card numbers,$hiddenattributes and encrypted casts are replaced with[REDACTED]— in model diffs, input, properties and URL query strings. - Mail bodies are never stored; recipients can be hashed (
mail.hash_recipients). - IPs can be anonymised (
http.capture.anonymize_ip), request input is off by default. - Recording never breaks your app: failures are reported, not thrown
(
AUDITOR_THROW=truein tests). - Entries are written after the response is sent, or through the queue (
AUDITOR_QUEUE). - Integrity: rows are chained with HMAC-SHA256;
auditor:verifydetects modified and removed rows. It cannot protect against someone who holds both the key and the database.
Limitations
Mass updates/deletes through the query builder, insert(), and pivot attach()/detach()
without a custom pivot model do not fire Eloquent events, so they are not recorded as
model changes.
Ecosystem
- rembon/laravel-auditor-filament: Filament 5 plugin with read-only
Audit entries and Model changes resources, an
AuditsRelationManagerfor any resource, and a stats widget. - rembon/laravel-auditor-pulse: Laravel Pulse cards for denied abilities, top model changes and the most active users.
Documentation
Development
composer test # unit + feature composer test:browser # dashboard in a real browser (needs `npx playwright install chromium`) composer analyse # Larastan composer serve # workbench with demo data at http://localhost:8000/auditor
See CONTRIBUTING.md. Report vulnerabilities privately — see SECURITY.md.
Credits
- Rembon Karya Digital
- DayCod
- Ade Yusuf
- All contributors
- Icons: Lucide (ISC)
License
MIT. See LICENSE.


