This tutorial shows how you can create your very specific event listener in Keycloak. Keycloak let's you hook into almost 100 different event types. The example we're building in this tutorial will send an email to an admin on every new registration. In this way somebody of the company will be notified whenever a new user signs up. The repository of the example can be found here.
How to create the listener?
In order to implement a custom event listener you need to impement the org.keycloak.events.EventListenerProvider
interface. The function onEvent
will be called on every event that happens in Keycloak. In this example we check for the REGISTER
event and send an email to an admin user. The class AdminUser
(see here) implements the Keycloak user model to provide a hard coded email to which the event listener sends the notification.
@Override
public void onEvent(Event event) {
if (EventType.REGISTER.equals(event.getType())) {
log.infof("## NEW %s EVENT", event.getType());
log.info("-----------------------------------------------------------");
RealmModel realm = this.model.getRealm(event.getRealmId());
UserModel newRegisteredUser = this.session.users().getUserById(event.getUserId(), realm);
String emailPlainContent = "New user registration\n\n" +
"Email: " + newRegisteredUser.getEmail() + "\n" +
"Username: " + newRegisteredUser.getUsername() + "\n" +
"Client: " + event.getClientId();
String emailHtmlContent = "<h1>New user registration</h1>" +
"<ul>" +
"<li>Email: " + newRegisteredUser.getEmail() + "</li>" +
"<li>Username: " + newRegisteredUser.getUsername() + "</li>" +
"<li>Client: " + event.getClientId() + "</li>" +
"</ul>";
DefaultEmailSenderProvider senderProvider = new DefaultEmailSenderProvider(session);
try {
senderProvider.send(session.getContext().getRealm().getSmtpConfig(), new AdminUser(), "Keycloak - New Registration", emailPlainContent, emailHtmlContent);
} catch (EmailException e) {
log.error("Failed to send email", e);
}
log.info("-----------------------------------------------------------");
}
}
In order to be able to register this custom event listener class in Keycloak you will need to implement org.keycloak.events.EventListenerProviderFactory
interface and return the newly created class in the create
method.
public class CustomEventListenerProviderFactory implements EventListenerProviderFactory {
@Override
public EventListenerProvider create(KeycloakSession keycloakSession) {
return new CustomEventListenerProvider(keycloakSession);
}
@Override
public void init(Config.Scope scope) {
}
@Override
public void postInit(KeycloakSessionFactory keycloakSessionFactory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "custom-event-listener";
}
}
The final step before we can package our listener is to create the following file src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
. This will make sure that Keycloak can discover the new Listener.
it.aboutbits.CustomEventListenerProviderFactory
You can find the file in the example repository here.
Bonus: Using keycloak services within listener
If you would like to use services from keycloak within your listener, like the email service in the example, then you have to add this file src/main/resources/META-INF/jboss-deployment-structure.xml
.
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-services" />
</dependencies>
</deployment>
</jboss-deployment-structure>
How to deploy the artifact?
Once you created the artifact you have to copy the jar into your keycloak installation ($KEYCLOAK_DIR/standalone/deployments/
).
If you are using docker to run your Keycloak instance you can do the following:
version: "3.7"
services:
keycloak:
image: jboss/keycloak:11.0.3
environment:
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: keycloak
DB_SCHEMA: public
DB_USER: keycloak
DB_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: password
volumes:
- ./custom-event-listener/target/custom-event-listener-0.0.1-SNAPSHOT.jar://opt/jboss/keycloak/standalone/deployments/custom-event-listener-0.0.1-SNAPSHOT.jar
depends_on:
- postgres
ports:
- 8080:8080
postgres:
image: postgres:12
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
ports:
- 5432:5432
mailhog:
image: mailhog/mailhog
ports:
- 8025:8025
How to enable the listener?
You're almost done. The listener should now be available in the list of event listeners. All you have to do now is to select the listener from the dropdown of available event listeners and save.
To see a running example checkout the repository and follow the instructions in the readme.