Keycloak’s event logging is designed to capture nearly every authentication and administrative action within your realm, providing a rich audit trail that’s often more comprehensive than people realize.
Let’s see it in action. Imagine a user attempting to log in. This is what a successful login event looks like in Keycloak’s event log:
{
"type": "LOGIN",
"realmId": "myrealm",
"clientId": "myclient",
"userId": "a1b2c3d4-e5f6-7890-1234-abcdef123456",
"ipAddress": "192.168.1.100",
"userSessionId": "abcdef1234567890abcdef1234567890",
"eventTimestamp": 1678886400000,
"details": {
"username": "testuser",
"redirectUri": "http://localhost:8080/callback"
}
}
This single JSON object tells us:
type: The action performed (LOGIN).realmId: Which realm the action occurred in.clientId: Which client application initiated the action.userId: The unique identifier of the user.ipAddress: Where the request originated from.userSessionId: The session identifier for this user.eventTimestamp: When the event occurred (Unix epoch milliseconds).details: Specific context for the event, like theusernameandredirectUri.
Keycloak logs events for a multitude of actions: user registration, password resets, administrative role changes, client creation, token issuance, and even failed attempts. This granular logging is crucial for security auditing, troubleshooting authentication flows, and understanding user behavior within your applications.
The core of Keycloak’s event logging is its Event SPI (Service Provider Interface). By default, Keycloak uses the DefaultEventListenerProvider which writes events to the database. However, you can configure it to send events to other destinations like Kafka, Syslog, or a custom provider.
To understand the levers you control, we primarily look at the Keycloak Admin Console. Navigate to your realm’s settings, and you’ll find an "Events" section. Here, you can:
- Enable/Disable Event Types: You can choose which types of events are logged. For instance, you might disable
IDENTITY_PROVIDER_LINKevents if they’re too noisy for your needs, or ensureLOGIN_ERRORevents are always captured. - Set Event Expiration: Define how long events are retained in the database. A common setting is
86400seconds (1 day) for active systems, or much longer for compliance-driven environments. - Configure Event Listeners: This is where you plug in custom logic or external systems. For example, to send events to Kafka, you’d configure a
KafkaEventListenerProviderwith your Kafka broker details.
The event configuration in standalone.xml (or standalone-ha.xml, etc.) is where the default provider is defined and where you can set global parameters like eventsExpiration and skipEventsIfNoListeners.
<subsystem xmlns="urn:jboss:domain:keycloak:server">
<spi name="events">
<default-provider>jpa</default-provider>
<provider name="jpa" enabled="true">
<properties>
<property name="eventsExpiration" value="86400"/>
</properties>
</provider>
<!-- Other providers like kafka, syslog can be configured here -->
</spi>
...
</subsystem>
This eventsExpiration property, set to 86400, means events older than 24 hours will be automatically purged from the Keycloak database by a background cleanup task.
The most surprising aspect is how often the details map can contain crucial, often overlooked, information. For example, a LOGIN_ERROR event might not just say "failed login"; its details could include specific error codes like invalid_credentials or user_disabled, or even the identityProvider that failed, which is vital for debugging federated identity issues.
The next logical step after mastering event logging is to think about how you’ll consume and analyze these events, especially for real-time security monitoring.