Keycloak Events
Overview
Keycloak is an open-source identity and access management solution that enables Single Sign-On (SSO), social login and standard protocols like OAuth2, OpenID Connect and SAML. It supports user federation, fine-grained authorization policies and multi-factor authentication. Easy to deploy and integrate, it secures applications and services with minimal coding.
- Vendor: Keycloak
- Supported environment: On-premise, Cloud
- Detection based on: Telemetry
- Supported application or feature: User Events
Warning
Important note - This format is currently in beta. We highly value your feedback to improve its performance.
Supported events
This integration supports the following event types:
- User Events
Configure
Prerequisites
- Administrator access to Keycloak Console
- Access to Sekoia.io Intakes page with write permissions
- A log concentrator to forward events to Sekoia.io
Create an intake
- Go to the intake page and create a new intake from the format Keycloak.
- Copy the intake key for later use in the forwarder configuration.
Enable User events in Keycloak
Step 1: Access Realm Settings
- Log in to the Keycloak Console as an administrator
-
Go to
Realm settings
-
Click
Eventstab
-
Select
jboss-loggingasEvent listeners -
Click
Save
-
Click
User events settingsTab
-
Enable
save events -
Click
Save
See Keycloak Documentation for more information.
Forward events to the concentrator
In the Keycloak configuration, set the following options to forward events to a log concentrator:
log(env:KC_LOG): addsyslogto the optionlog-syslog-endpoint(env:KC_LOG_SYSLOG_ENDPOINT): Set the IP address of the concentrator and the port dedicated for the intakelog-syslog-protocol(env:KC_LOG_SYSLOG_PROTOCOL): Set totcplog-syslog-output(env:KC_LOG_SYSLOG_OUTPUT): Set tojsonlog-syslog-json-format(env:KC_LOG_SYSLOG_JSON_FORMAT): Set toecsspi-events-listener--jboss-logging--success-level(env:KC_SPI_EVENTS_LISTENER_JBOSS_LOGGING_SUCCESS_LEVEL): Set toinfo
Using Environment Variables
export KC_LOG=syslog
export KC_LOG_SYSLOG_ENDPOINT=<ip_concentrator>:<intake_port>
export KC_LOG_SYSLOG_PROTOCOL=tcp
export KC_LOG_SYSLOG_OUTPUT=json
export KC_LOG_SYSLOG_JSON_FORMAT=ecs
export KC_SPI_EVENTS_LISTENER__JBOSS_LOGGING__SUCCESS_LEVEL=info
Using the keycloak.conf File
log=syslog
log-syslog-endpoint=<ip_concentrator>:<intake_port>
log-syslog-protocol=tcp
log-syslog-output=json
log-syslog-json-format=ecs
spi-events-listener-jboss-logging-success-level=info
Forward events to Sekoia.io
Please consult the Syslog Forwarding documentation to forward these logs to Sekoia.io.
Create a new configuration file in the ./extended_conf/ directory (create it if it does not exist):
vim ./extended_conf/12-keycloak.conf
with the following template:
module(load="imtcp")
input(type="imtcp" port="PORT" ruleset="remoteKeycloak")
template(name="SEKOIAIOTemplate" type="string" string="<%pri%>1 %timestamp:::date-rfc3339% %hostname% %app-name% %procid% LOG [SEKOIA@53288 intake_key=\"INTAKE_KEY\"] %msg%\n")
ruleset(name="remoteKeycloak"){
if($msg contains "org.keycloak.events") then {
action(
type="omfwd"
protocol="tcp"
target="intake.sekoia.io"
port="10514"
TCP_Framing="octet-counted"
StreamDriver="gtls"
StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="intake.sekoia.io"
Template="SEKOIAIOTemplate"
)
}
}
Note
Please change INTAKE_KEY with your actual intake key, as well as the PORT number.
Update the docker-compose.yml file of the Sekoia.io Forwarder to mount the extended conf:
volumes:
- ./intakes.yaml:/intakes.yaml
...
- ./extended_conf:/extended_conf
Raw Events Samples
In this section, you will find examples of raw logs as generated natively by the source. These examples are provided to help integrators understand the data format before ingestion into Sekoia.io. It is crucial for setting up the correct parsing stages and ensuring that all relevant information is captured.
{
"@timestamp": "2025-11-21T13:55:09.111222333Z",
"event.sequence": 4420,
"log.logger": "org.keycloak.events",
"log.level": "WARN",
"message": "type=\"CODE_TO_TOKEN_ERROR\", realmId=\"staging-realm\", realmName=\"staging\", clientId=\"test-client\", userId=\"null\", ipAddress=\"198.51.100.123\", error=\"invalid_code\", grant_type=\"authorization_code\"",
"process.thread.name": "executor-thread-4",
"process.thread.id": 30,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "staging"
}
{
"@timestamp": "2025-11-13T16:07:05.472632304Z",
"event.sequence": 2951,
"log.logger": "org.keycloak.events",
"log.level": "WARN",
"message": "type=\"LOGIN_ERROR\", realmId=\"00000000-0000-0000-0000-000000000000\", realmName=\"master\", clientId=\"security-admin-console\", userId=\"null\", ipAddress=\"1.2.3.4\", error=\"expired_code\", restart_after_timeout=\"true\"",
"process.thread.name": "executor-thread-1",
"process.thread.id": 25,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk-21.0.9.0.10-1.el9.x86_64/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "prod"
}
{
"@timestamp": "2025-11-21T10:15:23.123456789Z",
"event.sequence": 1001,
"log.logger": "org.keycloak.events",
"log.level": "INFO",
"message": "type=\"LOGIN\", realmId=\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\", realmName=\"production\", clientId=\"webapp-client\", userId=\"user-12345\", ipAddress=\"192.0.2.100\", auth_method=\"openid-connect\", redirect_uri=\"https://example.com/callback\"",
"process.thread.name": "executor-thread-5",
"process.thread.id": 42,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "prod"
}
{
"@timestamp": "2025-11-21T14:30:45.987654321Z",
"event.sequence": 5500,
"log.logger": "org.keycloak.events",
"log.level": "INFO",
"message": "type=\"LOGOUT\", realmId=\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\", realmName=\"production\", clientId=\"webapp-client\", userId=\"user-67890\", ipAddress=\"198.51.100.50\", redirect_uri=\"https://example.com/\"",
"process.thread.name": "executor-thread-3",
"process.thread.id": 18,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "prod"
}
{
"@timestamp": "2025-11-21T11:45:12.555555555Z",
"event.sequence": 3200,
"log.logger": "org.keycloak.events",
"log.level": "DEBUG",
"message": "type=\"REFRESH_TOKEN\", realmId=\"test-realm-id\", realmName=\"test\", clientId=\"mobile-app\", userId=\"user-abc123\", ipAddress=\"203.0.113.25\"",
"process.thread.name": "executor-thread-7",
"process.thread.id": 55,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "dev"
}
{
"@timestamp": "2025-11-21T09:22:33.777888999Z",
"event.sequence": 8750,
"log.logger": "org.keycloak.events",
"log.level": "DEBUG",
"message": "type=\"USER_INFO_REQUEST\", realmId=\"prod-realm-uuid\", realmName=\"corporate\", clientId=\"api-service\", userId=\"employee-555\", ipAddress=\"192.0.2.200\"",
"process.thread.name": "executor-thread-2",
"process.thread.id": 10,
"mdc": {},
"ndc": "",
"host.hostname": "example.com",
"process.name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"process.pid": 1,
"ecs.version": "1.12.2",
"data_stream.type": "logs",
"service.name": "Keycloak",
"service.version": "26.4.2",
"service.environment": "prod"
}
Detection section
The following section provides information for those who wish to learn more about the detection capabilities enabled by collecting this intake. It includes details about the built-in rule catalog, event categories, and ECS fields extracted from raw events. This is essential for users aiming to create custom detection rules, perform hunting activities, or pivot in the events page.
No related built-in rules was found. This message is automatically generated.
Event Categories
The following table lists the data source offered by this integration.
| Data Source | Description |
|---|---|
Web logs |
None |
Authentication logs |
None |
In details, the following table denotes the type of events produced by this integration.
| Name | Values |
|---|---|
| Kind | `` |
| Category | authentication |
| Type | denied, end, info, start |
Transformed Events Samples after Ingestion
This section demonstrates how the raw logs will be transformed by our parsers. It shows the extracted fields that will be available for use in the built-in detection rules and hunting activities in the events page. Understanding these transformations is essential for analysts to create effective detection mechanisms with custom detection rules and to leverage the full potential of the collected data.
{
"message": "{\"@timestamp\":\"2025-11-21T13:55:09.111222333Z\",\"event.sequence\":4420,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"WARN\",\"message\":\"type=\\\"CODE_TO_TOKEN_ERROR\\\", realmId=\\\"staging-realm\\\", realmName=\\\"staging\\\", clientId=\\\"test-client\\\", userId=\\\"null\\\", ipAddress=\\\"198.51.100.123\\\", error=\\\"invalid_code\\\", grant_type=\\\"authorization_code\\\"\",\"process.thread.name\":\"executor-thread-4\",\"process.thread.id\":30,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"staging\"}",
"event": {
"category": [
"authentication"
],
"code": "CODE_TO_TOKEN_ERROR",
"outcome": "failure",
"provider": "test-client",
"type": [
"denied"
]
},
"@timestamp": "2025-11-21T13:55:09.111222Z",
"error": {
"code": "invalid_code"
},
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "staging-realm",
"name": "staging"
},
"service": {
"environment": "staging"
}
},
"log": {
"level": "WARN",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"pid": 1,
"thread": {
"id": 30,
"name": "executor-thread-4"
}
},
"related": {
"ip": [
"198.51.100.123"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "198.51.100.123",
"ip": "198.51.100.123"
}
}
{
"message": "{\"@timestamp\":\"2025-11-13T16:07:05.472632304Z\",\"event.sequence\":2951,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"WARN\",\"message\":\"type=\\\"LOGIN_ERROR\\\", realmId=\\\"00000000-0000-0000-0000-000000000000\\\", realmName=\\\"master\\\", clientId=\\\"security-admin-console\\\", userId=\\\"null\\\", ipAddress=\\\"1.2.3.4\\\", error=\\\"expired_code\\\", restart_after_timeout=\\\"true\\\"\",\"process.thread.name\":\"executor-thread-1\",\"process.thread.id\":25,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk-21.0.9.0.10-1.el9.x86_64/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"prod\"}",
"event": {
"category": [
"authentication"
],
"code": "LOGIN_ERROR",
"outcome": "failure",
"provider": "security-admin-console",
"type": [
"denied"
]
},
"@timestamp": "2025-11-13T16:07:05.472632Z",
"error": {
"code": "expired_code"
},
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "master"
},
"service": {
"environment": "prod"
}
},
"log": {
"level": "WARN",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk-21.0.9.0.10-1.el9.x86_64/bin/java",
"pid": 1,
"thread": {
"id": 25,
"name": "executor-thread-1"
}
},
"related": {
"ip": [
"1.2.3.4"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "1.2.3.4",
"ip": "1.2.3.4"
}
}
{
"message": "{\"@timestamp\":\"2025-11-21T10:15:23.123456789Z\",\"event.sequence\":1001,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"INFO\",\"message\":\"type=\\\"LOGIN\\\", realmId=\\\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\\\", realmName=\\\"production\\\", clientId=\\\"webapp-client\\\", userId=\\\"user-12345\\\", ipAddress=\\\"192.0.2.100\\\", auth_method=\\\"openid-connect\\\", redirect_uri=\\\"https://example.com/callback\\\"\",\"process.thread.name\":\"executor-thread-5\",\"process.thread.id\":42,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"prod\"}",
"event": {
"category": [
"authentication"
],
"code": "LOGIN",
"provider": "webapp-client",
"type": [
"info"
]
},
"@timestamp": "2025-11-21T10:15:23.123456Z",
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "production"
},
"service": {
"environment": "prod"
}
},
"log": {
"level": "INFO",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"pid": 1,
"thread": {
"id": 42,
"name": "executor-thread-5"
}
},
"related": {
"ip": [
"192.0.2.100"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "192.0.2.100",
"ip": "192.0.2.100"
},
"user": {
"id": "user-12345"
}
}
{
"message": "{\"@timestamp\":\"2025-11-21T14:30:45.987654321Z\",\"event.sequence\":5500,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"INFO\",\"message\":\"type=\\\"LOGOUT\\\", realmId=\\\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\\\", realmName=\\\"production\\\", clientId=\\\"webapp-client\\\", userId=\\\"user-67890\\\", ipAddress=\\\"198.51.100.50\\\", redirect_uri=\\\"https://example.com/\\\"\",\"process.thread.name\":\"executor-thread-3\",\"process.thread.id\":18,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"prod\"}",
"event": {
"category": [
"authentication"
],
"code": "LOGOUT",
"provider": "webapp-client",
"type": [
"end"
]
},
"@timestamp": "2025-11-21T14:30:45.987654Z",
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "production"
},
"service": {
"environment": "prod"
}
},
"log": {
"level": "INFO",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"pid": 1,
"thread": {
"id": 18,
"name": "executor-thread-3"
}
},
"related": {
"ip": [
"198.51.100.50"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "198.51.100.50",
"ip": "198.51.100.50"
},
"user": {
"id": "user-67890"
}
}
{
"message": "{\"@timestamp\":\"2025-11-21T11:45:12.555555555Z\",\"event.sequence\":3200,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"DEBUG\",\"message\":\"type=\\\"REFRESH_TOKEN\\\", realmId=\\\"test-realm-id\\\", realmName=\\\"test\\\", clientId=\\\"mobile-app\\\", userId=\\\"user-abc123\\\", ipAddress=\\\"203.0.113.25\\\"\",\"process.thread.name\":\"executor-thread-7\",\"process.thread.id\":55,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"dev\"}",
"event": {
"category": [
"authentication"
],
"code": "REFRESH_TOKEN",
"provider": "mobile-app",
"type": [
"info"
]
},
"@timestamp": "2025-11-21T11:45:12.555555Z",
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "test-realm-id",
"name": "test"
},
"service": {
"environment": "dev"
}
},
"log": {
"level": "DEBUG",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"pid": 1,
"thread": {
"id": 55,
"name": "executor-thread-7"
}
},
"related": {
"ip": [
"203.0.113.25"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "203.0.113.25",
"ip": "203.0.113.25"
},
"user": {
"id": "user-abc123"
}
}
{
"message": "{\"@timestamp\":\"2025-11-21T09:22:33.777888999Z\",\"event.sequence\":8750,\"log.logger\":\"org.keycloak.events\",\"log.level\":\"DEBUG\",\"message\":\"type=\\\"USER_INFO_REQUEST\\\", realmId=\\\"prod-realm-uuid\\\", realmName=\\\"corporate\\\", clientId=\\\"api-service\\\", userId=\\\"employee-555\\\", ipAddress=\\\"192.0.2.200\\\"\",\"process.thread.name\":\"executor-thread-2\",\"process.thread.id\":10,\"mdc\":{},\"ndc\":\"\",\"host.hostname\":\"example.com\",\"process.name\":\"/usr/lib/jvm/java-21-openjdk/bin/java\",\"process.pid\":1,\"ecs.version\":\"1.12.2\",\"data_stream.type\":\"logs\",\"service.name\":\"Keycloak\",\"service.version\":\"26.4.2\",\"service.environment\":\"prod\"}",
"event": {
"category": [
"authentication"
],
"code": "USER_INFO_REQUEST",
"provider": "api-service",
"type": [
"info"
]
},
"@timestamp": "2025-11-21T09:22:33.777888Z",
"host": {
"name": "example.com"
},
"keycloak": {
"realm": {
"id": "prod-realm-uuid",
"name": "corporate"
},
"service": {
"environment": "prod"
}
},
"log": {
"level": "DEBUG",
"logger": "org.keycloak.events"
},
"process": {
"name": "/usr/lib/jvm/java-21-openjdk/bin/java",
"pid": 1,
"thread": {
"id": 10,
"name": "executor-thread-2"
}
},
"related": {
"ip": [
"192.0.2.200"
]
},
"service": {
"name": "Keycloak",
"version": "26.4.2"
},
"source": {
"address": "192.0.2.200",
"ip": "192.0.2.200"
},
"user": {
"id": "employee-555"
}
}
Extracted Fields
The following table lists the fields that are extracted, normalized under the ECS format, analyzed and indexed by the parser. It should be noted that infered fields are not listed.
| Name | Type | Description |
|---|---|---|
@timestamp |
date |
Date/time when the event originated. |
error.code |
keyword |
Error code describing the error. |
event.category |
keyword |
Event category. The second categorization field in the hierarchy. |
event.code |
keyword |
Identification code for this event. |
event.outcome |
keyword |
The outcome of the event. The lowest level categorization field in the hierarchy. |
event.provider |
keyword |
Source of the event. |
event.type |
keyword |
Event type. The third categorization field in the hierarchy. |
host.name |
keyword |
Name of the host. |
keycloak.realm.id |
keyword |
The unique identifier of the Keycloak realm |
keycloak.realm.name |
keyword |
The name of the Keycloak realm |
keycloak.service.environment |
keyword |
The deployment environment of the Keycloak service |
log.level |
keyword |
Log level of the log event. |
log.logger |
keyword |
Name of the logger. |
process.name |
keyword |
Process name. |
process.pid |
long |
Process id. |
process.thread.id |
long |
Thread ID. |
process.thread.name |
keyword |
Thread name. |
service.name |
keyword |
Name of the service. |
service.version |
keyword |
Version of the service. |
source.ip |
ip |
IP address of the source. |
user.id |
keyword |
Unique identifier of the user. |
For more information on the Intake Format, please find the code of the Parser, Smart Descriptions, and Supported Events here.