Skip to content

Impersonation Audit Trail

1. What does this feature do? (High-Level Overview)

Section titled “1. What does this feature do? (High-Level Overview)”

The Impersonation Audit Trail provides comprehensive logging and tracking of all impersonation activities. It records who impersonated whom, when, where, what actions they performed, and maintains a complete audit history for security, compliance, and troubleshooting purposes.

  • Superadmin: Full access to all audit logs and impersonation history.
  • Security Auditors: Can review impersonation activities for compliance and security monitoring.
  • Compliance Officers: Can access historical records for regulatory compliance.

Note: Audit log access permissions may vary based on organizational security policies.

  • Rule 1: All impersonation activities are automatically logged - logging cannot be disabled for impersonation actions.
  • Rule 2: Audit logs are immutable - they cannot be edited or deleted through normal application operations.
  • Rule 3: Sensitive data (passwords, tokens, API keys) is automatically filtered from audit logs.
  • Rule 4: Both the actor (impersonator) and effective user (target) are recorded for every action.
  • Rule 5: Audit logs include complete request/response details for troubleshooting.
  • Rule 6: Token hashes (not plain tokens) are stored for security.
  • Rule 7: Expired impersonation tokens are retained in the database for audit purposes before being cleaned up (default: 7 days after expiration).

API Endpoints (example - actual endpoints may vary):

  • Audit logs are stored in the database and can be accessed through administrative tools
  • Activity logs visible through activity log viewing interfaces

Database Tables:

  • impersonation_tokens - Token lifecycle tracking
  • audit_logs - Detailed request/action logging
  • activity_log - Spatie Activity Log entries for token changes

Scenario A: Understanding what gets logged

Section titled “Scenario A: Understanding what gets logged”

When an impersonation session is created:

The system logs the following information:

In impersonation_tokens table:

  • token_hash - SHA-256 hash of the JWT token
  • impersonation_id - Unique session identifier (UUID)
  • user_id - Target user being impersonated
  • created_by - Impersonator user ID
  • scopes - Permission scopes for the session
  • expires_at - Token expiration timestamp
  • ip_address - Client IP address
  • user_agent - Client user agent string
  • created_at - Session creation timestamp

In Spatie activity_log table:

  • Event type: “created”
  • Log name: “impersonation_tokens”
  • Subject: ImpersonationToken model
  • Causer: Impersonator user
  • Description: “Impersonation token created: {impersonator} impersonating {user}”
  • Properties: Impersonated user details, creator details, active status

In Laravel logs:

  • Level: INFO
  • Message: “Impersonation started”
  • Context: Impersonator ID/name, target user ID/name, impersonation ID, location ID, IP address, reason

When requests are made with an impersonation token:

The system logs each request in the audit_logs table:

{
"actor_id": 1, // Impersonator user ID
"effective_user_id": 123, // Target user ID
"impersonation_id": "uuid", // Session identifier
"action_type": "view", // view|list|create|update|delete
"resource_type": "Client", // Resource being accessed
"resource_id": 456, // Specific resource ID
"description": "Viewed client details",
"request_method": "GET",
"request_route": "/api/clients/456",
"request_url": "https://api.example.com/api/clients/456",
"request_payload": {"..."}, // Filtered request data
"response_status": 200,
"response_data": {"..."}, // Filtered response (truncated if large)
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0...",
"duration_ms": 245, // Request processing time
"created_at": "2026-03-31T13:15:00Z"
}

Usage tracking in impersonation_tokens table:

  • usage_count - Incremented with each request
  • last_used_at - Updated to current timestamp

When a session is stopped or revoked:

In impersonation_tokens table:

  • revoked_at - Revocation timestamp
  • revoked_by - User who revoked (if external revocation)
  • revoke_reason - Reason for revocation

In Spatie activity_log table:

  • Event type: “updated”
  • Properties: Shows changes to revoked_at, revoked_by, revoke_reason fields

In Laravel logs:

  • Level: INFO (stop) or WARNING (revoke)
  • Message: “Impersonation stopped” or “Impersonation revoked”
  • Context: Full session details including reason

Scenario B: Retrieving impersonation history for a specific session

Section titled “Scenario B: Retrieving impersonation history for a specific session”

Using the Service Layer (for developers):

use App\Services\AuditService;
// Get all audit logs for a specific impersonation session
$auditService = app(AuditService::class);
$logs = $auditService->getImpersonationLogs($impersonationId);
// Result includes:
// - All actions performed during the session
// - Actor and effective user for each action
// - Request/response details
// - Timestamps and durations

Scenario C: Retrieving all impersonation activities by an administrator

Section titled “Scenario C: Retrieving all impersonation activities by an administrator”

Using the Service Layer (for developers):

// Get all actions performed by a specific impersonator
$actorLogs = $auditService->getActorLogs($administratorUserId);
// Get all impersonation sessions where a user was the target
$effectiveUserLogs = $auditService->getEffectiveUserLogs($targetUserId);

Scenario D: Understanding token lifecycle through audit logs

Section titled “Scenario D: Understanding token lifecycle through audit logs”
  1. Creation: Activity log “created” event + Laravel INFO log
  2. Usage: Multiple audit_logs entries for each request + usage tracking updates
  3. Expiration: No explicit log entry, but next validation attempt logs failure
  4. Revocation: Activity log “updated” event + Laravel WARNING log
  5. Cleanup: Token deleted from database (after 7 days by default), but audit_logs remain

  • Q: How long are audit logs retained?

    • A:
      • Activity logs: Retained indefinitely by default (Spatie Activity Log configuration)
      • Audit logs: Retained based on organizational policy (no automatic cleanup)
      • Impersonation tokens: Deleted 7 days after expiration (configurable), but audit logs remain
      • Laravel logs: Retained according to log rotation configuration
  • Q: Can audit logs be deleted or modified?

    • A: Audit logs are designed to be immutable. Standard application operations do not allow modification or deletion. Only database administrators with direct database access could modify them, which would be a serious security violation.
  • Q: What sensitive data is filtered from audit logs?

    • A: The system automatically filters the following keys from request/response data:
      • password, password_confirmation
      • token, api_token, api_key
      • secret, client_secret
      • authorization header values
      • Any custom sensitive keys configured in config/impersonation.php
  • Q: What happens to audit logs if a user is deleted?

    • A: Audit logs are preserved even after user deletion. The actor_id and effective_user_id fields remain, providing historical context even if the user record no longer exists.
  • Q: How can I see what changed during an impersonation session?

    • A: Query the audit_logs table filtering by impersonation_id. This will show all requests made during that session, including what resources were accessed and what data was modified.
  • Q: Are read operations (GET requests) logged?

    • A: Yes, all requests made with an impersonation token are logged, including read operations. This provides complete visibility into what data was accessed during the session.

Purpose: Tracks token lifecycle and metadata

FieldDescription
idPrimary key
token_hashSHA-256 hash of JWT (unique)
impersonation_idUUID session identifier (unique)
user_idTarget user ID (FK to users)
created_byImpersonator user ID (FK to users)
scopesJSON array of permission scopes
expires_atToken expiration timestamp
revoked_atRevocation timestamp (NULL if active)
revoked_byUser who revoked (FK to users, NULL if not revoked)
revoke_reasonText reason for revocation
ip_addressClient IP at token creation
user_agentClient user agent at creation
last_used_atLast usage timestamp
usage_countNumber of requests made with token
created_atRecord creation timestamp
updated_atRecord update timestamp

Indexes: token_hash, impersonation_id, user_id, created_by, expires_at, revoked_at


Purpose: Detailed request-level logging for impersonation sessions

FieldDescription
idPrimary key
actor_idImpersonator user ID
effective_user_idTarget user ID
impersonation_idSession UUID
action_typeview, list, create, update, delete
resource_typeModel/resource being accessed
resource_idSpecific resource identifier
descriptionHuman-readable action description
request_methodHTTP method (GET, POST, etc.)
request_routeRoute pattern
request_urlFull request URL
request_payloadJSON filtered request data
request_headersJSON relevant headers
response_statusHTTP status code
response_dataJSON filtered response (truncated if > 10KB)
ip_addressClient IP address
user_agentClient user agent
duration_msRequest processing time (milliseconds)
created_atLog entry timestamp

Purpose: Model-level change tracking for impersonation tokens

FieldDescription
idPrimary key
log_name”impersonation_tokens”
descriptionHuman-readable description
subject_type”App\Models\ImpersonationToken”
subject_idToken ID
causer_type”App\Models\User”
causer_idUser who caused the change
propertiesJSON metadata (tracked fields, user details, status)
created_atActivity timestamp

Properties JSON structure:

{
"attributes": {
"impersonation_id": "uuid",
"user_id": 123,
"created_by": 1,
"scopes": ["impersonation"],
"expires_at": "2026-03-31T14:30:00Z",
"revoked_at": null,
"revoked_by": null,
"revoke_reason": null
},
"old": {...}, // For updated events
"user": {
"id": 123,
"name": "John Doe",
"email": "john.doe@example.com"
},
"creator": {
"id": 1,
"name": "Admin User"
},
"status": "active|expired|revoked",
"revoked_by_user": {...}, // If revoked
"changed_by_admin": true // If changed by admin
}

  • Token Security: Only SHA-256 hashes stored, never plain tokens
  • Sensitive Data Filtering: Automatic filtering of passwords, tokens, secrets
  • Response Truncation: Large responses truncated to prevent log bloat (> 10KB)
  • Encryption: Audit logs encrypted at rest (database-level encryption)
  • Immutable Logs: Cannot be modified through application
  • Complete Audit Trail: Every action tracked with actor and effective user
  • Timestamp Accuracy: All timestamps use server timezone consistently
  • User Attribution: Both impersonator and target user recorded
  • Reason Tracking: Optional reason field for compliance documentation
  • Impersonation Tokens: Deleted 7 days after expiration (configurable)
  • Audit Logs: No automatic cleanup (retain per policy)
  • Activity Logs: Retained indefinitely (can be configured)
  • Laravel Logs: Rotated according to logging configuration

Consider implementing monitoring for:

  • High frequency of impersonation sessions from a single admin
  • Impersonation of sensitive user accounts (e.g., other admins)
  • Long-duration impersonation sessions
  • Impersonation sessions that access sensitive resources
  • Failed impersonation attempts

Command: php artisan impersonation:cleanup

Purpose: Delete old expired impersonation tokens to maintain database health

Options:

  • --days=N - Delete tokens expired for more than N days (default: 7)
  • --force - Skip confirmation prompt

What it does:

  • Queries tokens where expires_at < now() - N days
  • Deletes matching tokens from database
  • Logs deletion count to Laravel log
  • Preserves audit logs (audit_logs table) even after token deletion

Recommended Schedule:

// In routes/console.php
Schedule::command('impersonation:cleanup --force')
->daily()
->at('03:00')
->timezone('America/New_York');

Example:

Terminal window
# Delete tokens expired for more than 7 days
php artisan impersonation:cleanup
# Delete tokens expired for more than 30 days
php artisan impersonation:cleanup --days=30
# Run without confirmation
php artisan impersonation:cleanup --force

  1. Always provide a reason: When starting an impersonation session, include a clear reason for audit purposes
  2. End sessions promptly: Stop impersonation sessions as soon as the task is complete
  3. Review audit logs regularly: Monitor impersonation activities for security anomalies
  4. Use appropriate TTL: Set shorter TTLs for sensitive operations
  5. Document policy: Establish organizational policies for when impersonation is appropriate
  6. Train administrators: Ensure admins understand the audit trail and their responsibilities
  7. Monitor high-risk actions: Flag when impersonation sessions access sensitive data or perform destructive operations
  8. Implement alerts: Set up notifications for unusual impersonation patterns