Admin and integrity

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.

4.x EasyAdmin HMAC signing Sensitive masking

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.