Artem Efimov

Keycloak extension · Apache-2.0

Keycloak Event Listener for RabbitMQ

Publish Keycloak user and admin events to RabbitMQ, so your services can react to logins, registrations and account changes as they happen.

A fork of aznamier/keycloak-event-listener-rabbitmq for Keycloak 26. Mizzle Studio has taken it under its wing: you can count on current releases that keep working with new Keycloak versions, and consumers written for 3.0.5 keep working too.

Download 4.1.0Source on GitHub

Maintained by Mizzle Studio

  • Release 4.1.0, Oct 17, 2026
  • Tested on Keycloak 26.0–26.8
  • Java 17 or later
  • RabbitMQ 3.x and 4.x
A queue named keycloak-events, bound to amq.topic with KK.EVENT.#: a login and a user created by an administrator arrive on top of earlier Keycloak events

What it does

Keycloak hands every user event (LOGIN, LOGOUT, REGISTER, LOGIN_ERROR, …) and every admin event (user created, role granted, client changed, …) of a realm to the listener, once you enable it in that realm.

After Keycloak commits the request, the listener publishes one JSON message per event to an exchange, amq.topic by default, with a routing key such as KK.EVENT.CLIENT.<realm>.<SUCCESS|ERROR>.<client>.<event type>.

Each consumer binds its own queue with the keys it needs: everything, one realm, only errors, only admin changes.

  1. Keycloakuser and admin events
  2. amq.topictopic exchange, a routing key per event
  3. Your queueseach bound with the keys it needs

Who it is for

Teams that run Keycloak 26 and need other services to react to its events: a user sync service that follows registrations and account changes, alerts on login errors, or a reaction to users deleted by administrators. If you use aznamier’s extension, your consumers keep working as they are.

Install

Download and check the jar

Every release has the jar and a keycloak-to-rabbit.sha256 file, both built by CI from the release tag. Check the jar before you install it: Keycloak runs provider jars with its full privileges.

VERSION=4.1.0
BASE=https://github.com/Mizzle-Studio/keycloak-event-listener-rabbitmq/releases/download/v$VERSION
curl -fLO "$BASE/keycloak-to-rabbit-$VERSION.jar"
curl -fLO "$BASE/keycloak-to-rabbit.sha256"
sha256sum --check keycloak-to-rabbit.sha256

On macOS, check it with shasum -a 256 --check keycloak-to-rabbit.sha256. Releases from 4.1.0 on also carry an SBOM and a signed build provenance attestation, which the GitHub CLI checks:

gh attestation verify keycloak-to-rabbit-$VERSION.jar --repo Mizzle-Studio/keycloak-event-listener-rabbitmq

Install it in Keycloak

  1. Put the jar into Keycloak’s providers/ directory (/opt/keycloak/providers/ in the container image) and remove any older keycloak-to-rabbit jar. Run kc.sh build if you start Keycloak with --optimized.
  2. Point the listener at your broker (see Configuration) and restart Keycloak.
  3. Enable the listener in each realm: Realm settings › Events › Event listeners, add keycloak-to-rabbitmq, Save. Or with kcadm.sh, whose list replaces the current one:
kcadm.sh update realms/myrealm -s 'eventsListeners=["jboss-logging","keycloak-to-rabbitmq"]'

For your own Keycloak image, the installation guide has a Dockerfile that downloads the jar of the release and checks its checksum while it builds, and examples for the Keycloak Operator and Helm charts.

Try it with Docker Compose

Keycloak, RabbitMQ and the listener on your machine, ready in about half a minute once the images are pulled:

git clone https://github.com/Mizzle-Studio/keycloak-event-listener-rabbitmq.git
cd keycloak-event-listener-rabbitmq/examples/docker-compose
docker compose up -d --wait

Log in as the demo user alice, then read the event back from the queue keycloak-events:

curl -s -o /dev/null -w '%{http_code}\n' \
  -d client_id=demo-app -d username=alice -d password=alice -d grant_type=password \
  http://localhost:8080/realms/demo/protocol/openid-connect/token

curl -s -u demo:demo -H 'content-type: application/json' \
  -d '{"count":1,"ackmode":"ack_requeue_false","encoding":"auto"}' \
  http://localhost:15672/api/queues/%2F/keycloak-events/get

The second command prints the message: the routing key KK.EVENT.CLIENT.demo.SUCCESS.demo-app.LOGIN, the AMQP properties and the JSON event. The RabbitMQ UI is at http://localhost:15672 (demo / demo), and docker compose down -v removes everything. It is not a production setup: Keycloak runs in development mode, with demo passwords.

Configuration

Each setting comes from Keycloak’s provider configuration (spi-events-listener-keycloak-to-rabbitmq-<name>), then from the environment variable KK_TO_RMQ_<NAME>, then the default. At startup the listener logs the value it uses for each one, passwords masked.

NameEnvironment variableDefaultNotes
urlKK_TO_RMQ_URLlocalhostthe broker’s host name, not a URI
portKK_TO_RMQ_PORT5672set the TLS port yourself, usually 5671
vhostKK_TO_RMQ_VHOSTemptyempty means /, RabbitMQ’s default virtual host; releases before 4.1.0 need / set
exchangeKK_TO_RMQ_EXCHANGEamq.topicmust exist; the listener does not declare it
usernameKK_TO_RMQ_USERNAMEadminneeds write permission on the exchange only
passwordKK_TO_RMQ_PASSWORDadminnever logged
use_tlsKK_TO_RMQ_USE_TLSfalseonly true enables TLS
trust_storeKK_TO_RMQ_TRUST_STOREemptyPKCS12 or JKS; empty means the JVM default, which includes Keycloak’s trusted certificates
trust_store_passKK_TO_RMQ_TRUST_STORE_PASSemptythe trust store’s password; never logged
key_storeKK_TO_RMQ_KEY_STOREemptyPKCS12 with a client certificate, for mutual TLS
key_store_passKK_TO_RMQ_KEY_STORE_PASSemptyalso the password of the key; never logged

Use the KK_TO_RMQ_* variables, the command line (--spi-events-listener-keycloak-to-rabbitmq-use_tls=true) or keycloak.conf, and keep the underscores in the names: Keycloak 26.8 ignores KC_SPI_… variables for the five settings with an underscore in their name. Every form, TLS and examples are in the configuration guide.

Compatibility

keycloak-to-rabbitKeycloakJavaRabbitMQ
4.1.026.0 and newer 26.x17 or newer (the Keycloak images ship 21)4.x and 3.x
upstream 3.0.5built against 21.1.2; 16 or newer according to its README8 or newer—

On every change, CI runs an integration test with real Keycloak and RabbitMQ containers and the built jar: on the latest patch release of every Keycloak 26 line from 26.0 to 26.7 and on 26.8.1 with RabbitMQ 4.3.6, and on 26.8.1 with RabbitMQ 3.13. Every week another workflow tests the latest release and the default branch on the newest Keycloak image, quay.io/keycloak/keycloak:latest; a failure opens an issue labelled keycloak-latest.

Release 4.1.0 passed the integration test on:

Message format

One JSON message per event. The routing keys (realm and client names lose their dots; <RESULT> is SUCCESS or ERROR):

KK.EVENT.CLIENT.<REALM>.<RESULT>.<CLIENT>.<EVENT_TYPE>        user events
KK.EVENT.ADMIN.<REALM>.<RESULT>.<RESOURCE_TYPE>.<OPERATION>   admin events
Bind withto receive
KK.EVENT.#everything
KK.EVENT.CLIENT.#all user events
KK.EVENT.ADMIN.#all admin events
KK.EVENT.*.myrealm.ERROR.#all errors of realm myrealm
KK.EVENT.CLIENT.*.SUCCESS.*.LOGINsuccessful logins in any realm
KK.EVENT.ADMIN.*.SUCCESS.USER.DELETEusers deleted by administrators

A login in realm demo through client demo-app: the routing key KK.EVENT.CLIENT.demo.SUCCESS.demo-app.LOGIN, the properties app_id=Keycloak, content_type=application/json and content_encoding=UTF-8, the header __TypeId__, and this body (details shortened):

{
  "@class" : "com.github.aznamier.keycloak.event.provider.EventClientNotificationMqMsg",
  "time" : 1792178809437,
  "type" : "LOGIN",
  "realmId" : "b43f6f2c-1a03-40d4-a3c2-6cd8df8e49b6",
  "clientId" : "demo-app",
  "userId" : "05fce3fd-ee8b-4d27-bbbd-de6f3a29820b",
  "sessionId" : "gIOG9-ZDDp96Liom5YidaEd1",
  "ipAddress" : "172.24.0.1",
  "details" : {
    "auth_method" : "openid-connect",
    "grant_type" : "password",
    "username" : "alice"
  }
}

Admin events, every field and the exact rules are in the message format guide, and consumers for Spring Boot, Node.js and Python in the consumer examples.

Migrating from aznamier 3.0.5

Consumers need no change: on the same Keycloak version this listener publishes the same routing keys, AMQP properties, headers and JSON fields as aznamier/keycloak-event-listener-rabbitmq 3.0.5. The provider id is still keycloak-to-rabbitmq, so realm settings and realm exports stay valid, and every setting keeps its name and its KK_TO_RMQ_* variable.

What changes on the Keycloak side:

Steps:

  1. Replace the jar in providers/ (or in your image) and run kc.sh build if you start Keycloak with --optimized.
  2. With TLS, make sure the broker certificate is trusted and issued for the host name in url.
  3. If you set options through KC_SPI_… variables, check the listener’s configuration: log lines after the upgrade.
  4. Restart Keycloak and watch for keycloak-to-rabbitmq ERROR lines.

Details, and moving from the focus-shift fork, are in the migration guide.

FAQ

How do I send Keycloak events to RabbitMQ?

Install this listener: put its jar into Keycloak’s providers/ directory, point it at your broker with KK_TO_RMQ_URL, KK_TO_RMQ_USERNAME and KK_TO_RMQ_PASSWORD, restart Keycloak and add keycloak-to-rabbitmq to the event listeners of each realm. From then on every user and admin event of that realm is published as JSON to an exchange, amq.topic by default, and your consumers bind queues with the routing keys they need.

Does it publish admin events?

Yes. Every admin event of a realm where the listener is enabled is published, such as a user created, a role granted or a client changed, with the routing key KK.EVENT.ADMIN.<realm>.<SUCCESS|ERROR>.<resource type>.<operation>, for example KK.EVENT.ADMIN.acme.SUCCESS.USER.CREATE. The changed resource is in the representation field, as JSON inside a string. The realm’s “Save events” settings don’t filter what the listener receives.

Which Keycloak versions are supported?

Keycloak 26.0 and newer 26.x, on Java 17 or newer. CI tests the jar on the latest patch release of every Keycloak 26 line from 26.0 to 26.7 and on 26.8.1, and a weekly workflow tests the newest Keycloak release. RabbitMQ 4.x and 3.x work; CI uses 4.3.6 and 3.13.

Is it a drop-in replacement for aznamier’s extension?

For your consumers, yes: the provider id keycloak-to-rabbitmq, the settings and environment variables, the Java class names in @class and __TypeId__, the routing keys and the JSON fields are the same as in 3.0.5 on the same Keycloak version, and contract tests written against 3.0.5 pin them. On the Keycloak side you replace the jar: it needs Keycloak 26 and Java 17, verifies the broker’s TLS certificate, and from 4.1.0 on reads an empty vhost as /.

How do I verify a release?

Each release has keycloak-to-rabbit.sha256 next to the jar: run sha256sum --check keycloak-to-rabbit.sha256, or on macOS shasum -a 256 --check keycloak-to-rabbit.sha256. Releases from 4.1.0 on also carry a CycloneDX SBOM and a signed build provenance attestation, which gh attestation verify keycloak-to-rabbit-4.1.0.jar --repo Mizzle-Studio/keycloak-event-listener-rabbitmq checks. The build is reproducible: building the release tag with Temurin 21 gives the same checksum.

What happens when RabbitMQ is down?

Keycloak keeps working: requests go on, and their events are dropped and logged. Delivery is at most once, with no retries and no buffer, so keep Keycloak’s own event store as the record if you need a complete audit trail. Before the first connection, a broker host that doesn’t answer can hold requests for up to the client’s 60-second connect timeout; once connected, the client reconnects in the background, and during a RabbitMQ memory or disk alarm events are dropped instead of holding up logins.