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/
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
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.
- Keycloakuser and admin events
- amq.topictopic exchange, a routing key per event
- 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
- Put the jar into Keycloak’s
providers/directory (/opt/keycloak/providers/in the container image) and remove any olderkeycloak-to-rabbitjar. Runkc.sh buildif you start Keycloak with--optimized. - Point the listener at your broker (see Configuration) and restart Keycloak.
- Enable the listener in each realm: Realm settings › Events › Event listeners, add
keycloak-to-rabbitmq, Save. Or withkcadm.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.
| Name | Environment variable | Default | Notes |
|---|---|---|---|
url | KK_TO_RMQ_URL | localhost | the broker’s host name, not a URI |
port | KK_TO_RMQ_PORT | 5672 | set the TLS port yourself, usually 5671 |
vhost | KK_TO_RMQ_VHOST | empty | empty means /, RabbitMQ’s default virtual host; releases before 4.1.0 need / set |
exchange | KK_TO_RMQ_EXCHANGE | amq.topic | must exist; the listener does not declare it |
username | KK_TO_RMQ_USERNAME | admin | needs write permission on the exchange only |
password | KK_TO_RMQ_PASSWORD | admin | never logged |
use_tls | KK_TO_RMQ_USE_TLS | false | only true enables TLS |
trust_store | KK_TO_RMQ_TRUST_STORE | empty | PKCS12 or JKS; empty means the JVM default, which includes Keycloak’s trusted certificates |
trust_store_pass | KK_TO_RMQ_TRUST_STORE_PASS | empty | the trust store’s password; never logged |
key_store | KK_TO_RMQ_KEY_STORE | empty | PKCS12 with a client certificate, for mutual TLS |
key_store_pass | KK_TO_RMQ_KEY_STORE_PASS | empty | also 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-rabbit | Keycloak | Java | RabbitMQ |
|---|---|---|---|
| 4.1.0 | 26.0 and newer 26.x | 17 or newer (the Keycloak images ship 21) | 4.x and 3.x |
| upstream 3.0.5 | built against 21.1.2; 16 or newer according to its README | 8 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:
- Keycloak 26.0.8 · RabbitMQ 4.3.6
- Keycloak 26.1.5 · RabbitMQ 4.3.6
- Keycloak 26.2.5 · RabbitMQ 4.3.6
- Keycloak 26.3.5 · RabbitMQ 4.3.6
- Keycloak 26.4.7 · RabbitMQ 4.3.6
- Keycloak 26.5.7 · RabbitMQ 4.3.6
- Keycloak 26.6.4 · RabbitMQ 4.3.6
- Keycloak 26.7.5 · RabbitMQ 4.3.6
- Keycloak 26.8.1 · RabbitMQ 3.13.7
- Keycloak 26.8.1 · RabbitMQ 4.3.6
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 with | to 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.*.LOGIN | successful logins in any realm |
KK.EVENT.ADMIN.*.SUCCESS.USER.DELETE | users 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-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:
- It needs Keycloak 26.0 or newer and Java 17 or newer; 3.0.5 was built against Keycloak 21.1.2 and Java 8. WildFly-based Keycloak is not supported.
- With
use_tls=truethe broker certificate and host name are verified, and a failed TLS setup means no connection, never plain AMQP. - An empty
vhost, the default, means RabbitMQ’s default virtual host/from 4.1.0 on. If a 3.0.5 setup delivered events with an emptyvhost, they went to a virtual host named"": move the exchange and its queues to another virtual host and setvhostto its name. - The jar bundles
amqp-client5.37.0 and nothing else; SLF4J and Netty come from Keycloak.
Steps:
- Replace the jar in
providers/(or in your image) and runkc.sh buildif you start Keycloak with--optimized. - With TLS, make sure the broker certificate is trusted and issued for the host name in
url. - If you set options through
KC_SPI_…variables, check the listener’sconfiguration:log lines after the upgrade. - Restart Keycloak and watch for
keycloak-to-rabbitmq ERRORlines.
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.
Source, releases and support
- Repository on GitHubthe code, the docs and the Docker Compose quick start
- Releasesthe jar, its checksum and its SBOM
- Changelogwhat changed in each release, and what to do when you upgrade
- QuestionsDiscussions, Q&A
- Bugs and ideasissues, with a form that asks for the versions and the listener’s log lines
- Report a vulnerabilityprivately, never in a public issue
Maintained by Mizzle Studio. The latest release gets fixes, security fixes included; support is best effort.
The original listener is the work of aznamier and the upstream contributors, under the Apache License 2.0. Keycloak and RabbitMQ are trademarks of their respective owners; this project is not affiliated with or endorsed by them.