Review audit logs without losing integrity.
Use EasyAdmin for operational review, Symfony profiler for development visibility, and integrity tools to detect tampering or protect transport payloads.
EasyAdmin Integration
Install EasyAdmin, then add the bundle's audit log CRUD controller to your dashboard menu.
composer require easycorp/easyadmin-bundle
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Rcsofttech\AuditTrailBundle\Controller\Admin\AuditLogCrudController;
final class DashboardController extends AbstractDashboardController
{
public function configureMenuItems(): iterable
{
yield MenuItem::linkTo(AuditLogCrudController::class, 'Audit Logs', 'fas fa-history');
}
}
audit_trail:
easyadmin:
permission: 'ROLE_ADMIN'
export_limit: 50000
Install bundle assets so custom diff styling, action badges, and revert modals load correctly.
php bin/console assets:install public
EasyAdmin export applies the active admin filters first, then enforces
easyadmin.export_limit. Transaction drill-down pagination accepts only one cursor at
a time: afterId or beforeId, not both.
Symfony Profiler
When WebProfilerBundle is installed, the profiler integration activates
automatically in development and test environments.
- Toolbar badge with audit count for the current request.
- Profiler panel with action, entity, fields, user, transaction hash, and timestamp.
- Summary tab with create, update, delete, and other action totals.
Security & Integrity
Enable signing when audit logs must be tamper-evident. Configure a stable secret and keep it out of the repository.
audit_trail:
integrity:
enabled: true
secret: '%env(string:AUDIT_INTEGRITY_SECRET)%'
algorithm: 'sha256'
# Set this in your deployment secret store.
# Use a stable, high-entropy value and keep it out of the repository.
AUDIT_INTEGRITY_SECRET='replace-with-at-least-32-random-characters'
Verify Stored Logs
php bin/console audit:verify-integrity
Verification checks stored signatures and reports records that no longer match their signed representation. Treat a mismatch as a serious security incident and investigate database access.
Stored signatures cover the entity identity and action, old and new values,
changed_fields, user and request metadata, transaction hash, persisted context,
and creation timestamp. Persisted context larger than 65,536 bytes is truncated to a safe marker
payload before storage and signing.
Sensitive Data Masking
Mask sensitive values so audit payloads do not store secrets in clear text.
<?php
declare(strict_types=1);
use Doctrine\ORM\Mapping as ORM;
use Rcsofttech\AuditTrailBundle\Attribute\Auditable;
use Rcsofttech\AuditTrailBundle\Attribute\Sensitive;
#[ORM\Entity]
#[Auditable]
class CustomerProfile
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public private(set) ?int $id = null;
public function __construct(
#[ORM\Column(length: 255)]
#[\SensitiveParameter]
private string $passwordHash,
#[ORM\Column(length: 32)]
#[Sensitive(mask: '****')]
private string $ssn,
) {
}
}
Transport Payload Signing
When integrity is enabled, HTTP payloads carry an X-Signature header and queue
payloads carry signature metadata through a Messenger stamp.
POST /api/logs HTTP/1.1
X-Signature: a1b2c3d4...
Content-Type: application/json
{ "entity_class": "App\\Entity\\User", "action": "update" }
<?php
declare(strict_types=1);
use Rcsofttech\AuditTrailBundle\Message\Stamp\SignatureStamp;
$signature = $envelope->last(SignatureStamp::class)?->signature;
The entity-level signature field protects the stored audit record for long-term
integrity. Transport signatures protect the outbound HTTP or Messenger payload in transit and
are generated just before delivery.