Custom Events
Beyond the automatic monitors, any security-relevant action in your application can be reported through the Siem facade — data exports, permission changes, admin impersonation, API key creation, payment anomalies.
The one-liner: Siem::log()#
use Inqaba\Gatekeeper\Facades\Siem;
use Inqaba\Gatekeeper\Events\Severity;
Siem::log(
'export_download', // event.action
'Customer data export downloaded', // message
Severity::High, // severity (default: Medium)
['rows' => 12000, 'format' => 'csv'], // laravel.context
$request->user() // user (optional)
);
Request context (IP, user agent, URL, method) is captured automatically when a request is available. The action lands in event.action, so your SOC can alert on it exactly like a built-in event.
The fluent builder: Siem::event()#
For catalog event types, or when you need finer control:
use Inqaba\Gatekeeper\Events\EventType;
Siem::event(EventType::AccessDenied)
->user($request->user())
->fromRequest($request)
->outcome('failure')
->with(['ability' => 'orders.export', 'order_id' => $order->id])
->report();
Builder methods:
| Method | Purpose |
|---|---|
severity(Severity $s) |
Override the type's default severity |
message(string $m) |
Override the default human-readable message |
outcome(string $o) |
success, failure or unknown (ECS event.outcome) |
user(?Authenticatable $u) |
Attach user.id / user.name |
fromRequest(?Request $r) |
Capture IP, user agent, URL, method |
with(array $context) |
Merge into laravel.context (redacted before shipping) |
report() |
Ship it |
A real-world example: authorization failures#
Laravel doesn't fire an event when a policy denies access, but a Gate::after hook makes every denial SOC-visible:
// AppServiceProvider::boot()
use Illuminate\Support\Facades\Gate;
use Inqaba\Gatekeeper\Facades\Siem;
use Inqaba\Gatekeeper\Events\EventType;
Gate::after(function ($user, string $ability, ?bool $result) {
if ($result === false) {
Siem::event(EventType::AccessDenied)
->user($user)
->fromRequest(request())
->with(['ability' => $ability])
->report();
}
});
Now repeated access_denied events from one user probing abilities they don't have becomes a hunting query in your SIEM.
Other places worth instrumenting#
- Sensitive reads — bulk exports, report downloads, PII access
- Privilege changes — role grants, permission edits, admin impersonation start/stop
- Credential lifecycle — API token created/revoked, 2FA disabled, recovery codes viewed
- Payment anomalies — refund storms, failed charge bursts, currency mismatches
- Tenant boundaries — any cross-tenant access attempt in a multi-tenant app
Blocking IPs from your own logic#
The blocklist is exposed on the facade, so your own detections can feed it:
Siem::blockIp('203.0.113.7', minutes: 120, reason: 'fraud-model-score');
Siem::unblockIp('203.0.113.7');
Siem::blocklist()->isBlocked('203.0.113.7'); // bool
Siem::blocklist()->entry('203.0.113.7'); // ['reason' => ..., 'blocked_at' => ...]
IPs and CIDR ranges listed in blocklist.never_block are silently refused — health checkers and office ranges can never be locked out. See IP Blocklist.