Skip to content

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

  1. Go to the intake page and create a new intake from the format Keycloak.
  2. Copy the intake key for later use in the forwarder configuration.

Enable User events in Keycloak

Step 1: Access Realm Settings

  1. Log in to the Keycloak Console as an administrator
  2. Go to Realm settings

    Step - 01.png

  3. Click Events tab

    Step - 02.png

  4. Select jboss-logging as Event listeners

  5. Click Save

    Step - 03.png

  6. Click User events settings Tab

    Step - 04.png

  7. Enable save events

  8. Click Save

    Step - 03.png

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): add syslog to the option
  • log-syslog-endpoint (env: KC_LOG_SYSLOG_ENDPOINT): Set the IP address of the concentrator and the port dedicated for the intake
  • log-syslog-protocol (env: KC_LOG_SYSLOG_PROTOCOL): Set to tcp
  • log-syslog-output (env: KC_LOG_SYSLOG_OUTPUT): Set to json
  • log-syslog-json-format (env: KC_LOG_SYSLOG_JSON_FORMAT): Set to ecs
  • spi-events-listener--jboss-logging--success-level (env: KC_SPI_EVENTS_LISTENER_JBOSS_LOGGING_SUCCESS_LEVEL): Set to info

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.

Further reading