Field Control
Not every column belongs in an audit log. Timestamps, cached counters, and sensitive fields like passwords should be filtered out. AuditChain provides three mechanisms for this.
Include Specific Fields
Use $auditInclude to audit only the listed fields. Everything else is ignored:
class User extends Model implements Auditable { use HasAuditTrail; protected array $auditInclude = ['name', 'email', 'role']; }
When a User is updated, only changes to name, email, or role appear in old_values and new_values.
Exclude Specific Fields
Use $auditExclude to exclude specific fields while auditing everything else:
class User extends Model implements Auditable { use HasAuditTrail; protected array $auditExclude = ['last_login_at', 'login_count']; }
Automatic Exclusion of Hidden Fields
Fields listed in the model's $hidden array are automatically excluded from audit values. This prevents passwords, API tokens, and other secrets from being recorded:
class User extends Model implements Auditable { use HasAuditTrail; protected $hidden = ['password', 'remember_token']; // password and remember_token are automatically excluded from audit logs }
This happens in addition to any $auditExclude fields. You do not need to list $hidden fields in $auditExclude.
Security Blocklist
Regardless of $auditInclude, $auditExclude, or $hidden configuration, the following fields are always excluded from audit logs:
passwordremember_tokentwo_factor_secrettwo_factor_recovery_codes
This blocklist is hardcoded and cannot be overridden. It acts as a safety net to prevent sensitive authentication data from ever appearing in the audit trail, even if a developer accidentally removes these fields from $hidden or adds them to $auditInclude.
$hidden Capture at Boot Time
The model's $hidden fields are captured once at boot time (when the trait is initialized). This means that calling $model->makeVisible('password') at runtime does not affect which fields are excluded from audit logs. The original $hidden list is immune to runtime modifications, preventing accidental exposure of sensitive fields.
Precedence
The rules are applied in this order:
- If
$auditIncludeis set, only those fields are kept - Fields in
$auditExcludeare removed - Fields in
$hidden(captured at boot time) are removed - Fields in the security blocklist are removed
If both $auditInclude and $auditExclude are set, inclusion is applied first, then exclusion. In practice, use one or the other.
What Gets Filtered
Field control applies to the old_values and new_values columns on automatic CRUD events. For custom events where you provide values manually via audit(), the values are stored as-is — field control does not apply.
Practical Example
A typical model with mixed concerns:
class Account extends Model implements Auditable { use HasAuditTrail; protected $hidden = ['api_secret']; protected array $auditExclude = [ 'last_seen_at', 'notifications_read_at', ]; }
This audits all meaningful changes while excluding the API secret (via $hidden) and noisy timestamp fields (via $auditExclude).