Skip to content

Audit Logging

The starter includes a comprehensive audit logging system that automatically tracks all significant user actions and data changes throughout your application. This provides a complete historical record for compliance, security investigations, and debugging.

Compliance & Regulations

Many Northwestern applications handle sensitive data subject to regulations requiring audit trails:

  • FERPA - Student education records
  • HIPAA - Healthcare information
  • University Policies - Administrative data retention requirements

Security & Forensics

Audit logs help detect and investigate security incidents:

  • Unauthorized access attempts
  • Suspicious data modifications
  • Account compromise indicators
  • Privilege escalation attempts

Debugging & Troubleshooting

Audit trails assist with diagnosing issues:

  • Understanding how data reached its current state
  • Identifying when changes were made
  • Determining who made specific changes
  • Reproducing reported issues

Accountability & Transparency

Complete audit trails provide:

  • Attribution for all actions
  • Transparency in administrative processes
  • Evidence for dispute resolution
  • Historical context for decisions

All models extending BaseModel automatically log the following Eloquent events with complete before/after state:

  • Created - When a new record is inserted
  • Updated - When an existing record is modified
  • Deleted - When a record is deleted (including soft deletes)
  • Restored - When a soft-deleted record is restored

Each audit log entry includes:

  • Event Type - The operation performed (created, updated, deleted, restored)
  • User - Who performed the action (authenticated user)
  • Timestamp - Exactly when the change occurred
  • Old Values - The state before the change (for updates and deletes)
  • New Values - The state after the change (for creates and updates)
  • User Agent - The browser/client that made the request
  • IP Address - Where the request originated from
  • URL - The route where the action occurred

Beyond automatic model events, the system logs custom events for critical operations:

Role Assignment & Removal

When roles are assigned to or removed from users:

  • User receiving the role change
  • Role being assigned/removed
  • Before state (previous roles)
  • After state (new roles)
  • User who made the change
  • Timestamp of the change

Permission Syncing

When a role’s permissions are modified:

  • Role whose permissions changed
  • Old permission set
  • New permission set
  • User who made the change
  • Timestamp of the sync

Impersonation Sessions

When administrators impersonate users:

  • When impersonation starts
  • Who is being impersonated
  • Who started the impersonation
  • When impersonation ends
  • Actions performed during impersonation

Certain fields can be excluded from audit logs to prevent storing sensitive or irrelevant data. You can configure exclusions at the model level:

// Within an Eloquent model extending BaseModel
protected array $auditExclude = [
'password',
'remember_token',
];

Security

Prevent sensitive data from being stored in audit logs:

  • Passwords (even hashed)
  • Access tokens
  • Encryption keys
  • OAuth secrets

Volume Control

Exclude fields that change too frequently:

  • Session timestamps
  • Cache counters
  • Temporary flags
  • Analytics data

Relevance

Skip technical fields not meaningful for audits:

  • Internal system flags
  • Framework metadata
  • Computed values

Storage Efficiency

Reduce audit table size and improve performance:

  • Less disk space usage
  • Faster queries
  • Easier log analysis

For actions that don’t fit standard CRUD operations, you can log custom audit events. The AuditsPermissions and AuditsRoles traits demonstrate this pattern.


By default, Laravel Auditing disables audit logging for console commands (the audit.console config is false). This means seeders that create or update Auditable models — such as RoleSeeder and PermissionSeeder — would not produce audit entries by default.

For production seeders that manage security-relevant data (roles, permissions, stakeholder assignments), this creates a gap in the audit trail. The AuditsSeederChanges trait solves this by registering the AuditableObserver directly on specified models.

Add the trait to your seeder and wrap the seeding logic in withAuditing():

app/Domains/Auth/Seeders/RoleSeeder.php
use App\Domains\Core\Seeders\Concerns\AuditsSeederChanges;
class RoleSeeder extends Seeder implements IdempotentSeederInterface
{
use AuditsSeederChanges;
public function run(): void
{
$this->withAuditing([Role::class], function () {
// Role creation and permission syncing logic...
});
}
}
SeederAudited ModelWhat gets audited
RoleSeederRoleRole creation, attribute updates
PermissionSeederPermissionPermission creation, metadata updates

The StakeholderSeeder uses assignRoleWithAudit() instead, which fires custom audit events that bypass the console check entirely.