struct

KemalIdentity::SecurityEvent

Inherits Struct < Value < Object

One thing that happened, on its way to a SIEM.

Why the correlation fields are typed and the rest is not

blueprints/0025-maturity-validation-results.md (OPS-02) measured what a consumer could actually build: a Log::Backend subscribed to kemal_identity.* receives every event, and the fields arrive in a loosely-typed bag. So an adapter matches on message strings and reads keys by name, a rename is a silent breakage, and nothing tells it which fields it can rely on.

What a SIEM correlates on is a short, stable list: who, which credential, which tenant, from where, and why. Those are getters here, so a rename is a compile error at every consumer. The event-specific remainder — a role name, a factor id, a count — stays in data, because typing forty event shapes would freeze forty things to gain nothing an adapter uses.

What is structurally absent

No raw credential, no digest, no password, no token. docs/02-security-model.md requires it and the emitting call sites never had them; nothing here can reintroduce one, because every field is a String? the shard populated deliberately.

Constructors

new(name : String, severity : ::Log::Severity, at : Time, subject : String | Nil = nil, credential : String | Nil = nil, tenant : String | Nil = nil, ip : String | Nil = nil, reason : String | Nil = nil, data : Hash(String, String) = {} of String => String)
Source

Instance methods

alarming?

Whether this is an event an operator should be woken for. The severities the shard uses deliberately: error for something broken, warn for something suspicious.

Source
credential

The credential that proved the request, when one did — a session id, a token id, a jti. Never the credential itself.

Source
data

Everything the event carried that is not one of the above, verbatim.

Source
ip

The source address, when the caller passed one in. Absent rather than guessed: the shard does not read a proxy header to invent it.

Source
name

The event name, as README.md's catalogue lists it: "authentication.failed", "session.rotated", "authz.denied".

Source
reason

Why, for the events that carry a reason: a FailureReason, an Authz::DenialReason, or an application authorizer's own code. Audit only — no response varies with it.

Source
severity
Source
subject

The account this is about, when the event has one. Principal#subject.

Source
tenant
Source