How to Write a Custom Event Handler in WSO2 Identity Server (With Debugging Tips)

Achini Udari Jayasena
4 min readFeb 13, 2025

--

A Journey into WSO2 IS Event Handling

WSO2 Identity Server (WSO2 IS) provides a powerful event-driven architecture that allows extending its functionality via custom event handlers [1]. Whether you want to log authentication attempts, enforce security policies, or integrate external services, writing a custom event handler is the way to go.

In this blog, I will walk you through everything I learned while writing my first custom event handler — from setting up the project to debugging deployment issues

🔍 What Are Event Handlers in WSO2 IS?

WSO2 IS uses an event-driven model to handle various identity-related events like user authentication, user creation, role updates, etc.

  • Pre-event handlers → Execute before an action (e.g., validating user input before registration).
  • Post-event handlers → Execute after an action (e.g., logging login attempts).

All event handlers extend AbstractEventHandler and override handleEvent(Event event).

🛠 When Should You Write a Custom Event Handler?

✅ You need to extend existing functionality (e.g., logging login attempts).
✅ You want to trigger an external service when an event occurs. (e.g.,Send notifications, audit logs, or integrate with external systems.)
✅ The default handlers do not meet your specific use case

✅Detect suspicious login activity, enforce account locks, or handle consent deletion.

🛠 Step 1: Setting Up the Maven Project

Create a Maven project with the following pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>wso2is-events</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<repository>
<id>wso2-public-maven-repo</id>
<url>https://maven.wso2.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.event</artifactId>
<version>7.7.163</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>5.1.9</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-ManifestVersion>2</Bundle-ManifestVersion>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>org.example</Export-Package>
<Import-Package>
org.osgi.framework,
org.wso2.carbon.identity.event,
org.wso2.carbon.identity.event.handler,
org.wso2.carbon.identity.event.exception,
org.wso2.carbon.identity.event.IdentityEventConstants
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

🔹 Common Mistake: If you miss the maven-bundle-plugin, WSO2 will not recognize your JAR as an OSGi bundle!

🚀 Step 2: Writing the Custom Event Handler

Create CustomEventUserReg.java inside src/main/java/org/example/:

package org.example;

import org.osgi.service.component.annotations.Component;
import org.wso2.carbon.identity.event.IdentityEventConstants;
import org.wso2.carbon.identity.event.IdentityEventException;
import org.wso2.carbon.identity.event.event.Event;
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

import java.util.Map;

@Component(
name = "org.example.CustomEventUserReg",
immediate = true
)
public class CustomEventUserReg extends AbstractEventHandler {

private static final Log log = LogFactory.getLog(CustomEventUserReg.class);

@Override
public String getName() {
return "CustomEventUserReg";
}

@Override
public void handleEvent(Event event) throws IdentityEventException {
if (IdentityEventConstants.EventName.POST_AUTHENTICATION.equals(event.getEventName())) {
Map<String, Object> properties = event.getEventProperties();
String username = (String) properties.get(IdentityEventConstants.EventProperty.USER_NAME);
Boolean isAuthenticated = (Boolean) properties.get(IdentityEventConstants.EventProperty.AUTHENTICATION_STATUS);

log.info("Handling POST_AUTHENTICATION event for user: " + username);
log.info("Authentication success status: " + isAuthenticated);
}
}
}

2️⃣ UserRegistrationCustomEventHandlerComponent.java

This class registers the CustomEventUserReg event handler as an OSGi service.

package org.example;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Component;
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;

@Component(
name ="org.example.UserRegistrationCustomEventHandlerComponent",
immediate = true
)

public class UserRegistrationCustomEventHandlerComponent {

private static final Log log = LogFactory.getLog(UserRegistrationCustomEventHandlerComponent.class);

protected void activate (ComponentContext context){
try {
BundleContext bundleContext = context.getBundleContext();
CustomEventUserReg customEventHandler = new CustomEventUserReg();
bundleContext.registerService(AbstractEventHandler.class.getName(), new CustomEventUserReg(), null);
log.info("CustomEventHandler successfully activated and registered as an OSGi service.");

}catch (Exception e){
log.error("error while activating CustomEventHandler");
}
}
}

🔧 Step 3: Deploying the Event Handler

1️⃣ Build the JAR file

mvn clean install

2️⃣ Copy it to WSO2 IS

cp target/wso2is-events-1.0-SNAPSHOT.jar <WSO2_IS_HOME>/repository/components/dropins/

3️⃣ Add Configuration to deployment.toml

[[event_handler]]
name = "CustomEventUserReg"
subscriptions = ["POST_AUTHENTICATION"]

4️⃣ Restart WSO2 IS

cd <WSO2_IS_HOME>/bin
./wso2server.sh

🔍 Step 4: Debugging Tips

If the event handler does not work, follow these steps:

ls -l <WSO2_IS_HOME>/repository/components/dropins/

1️⃣ Check if the JAR is loaded

ls -l <WSO2_IS_HOME>/repository/components/dropins/

✅ Ensure your JAR is inside the dropins/ folder.

2️⃣ Check OSGi Bundle Status

Add below configuration in <IS_HOME>/repository/conf/deployment.toml

[osgi.console]
enable = true
port = 5555

Start the OSGi console:

./wso2server.sh -DosgiConsole

List active bundles:

osgi> ss | grep CustomEventUserReg

3️⃣ Check Logs

grep "CustomEventUserReg" <WSO2_IS_HOME>/repository/logs/wso2carbon.log

✅ If logs don’t appear, the handler might not be registered.

4️⃣ Verify Package Imports

osgi> packages org.wso2.carbon.identity.event

✅ Ensure event and event.handler are available

Check if the Bundle is Installed

osgi> ss | grep wso2is-events

If your bundle is not listed, it means WSO2 Identity Server is not detecting it.

If the bundle is not start start manually

Start <bundleId>

Final Thoughts

Writing a custom event handler in WSO2 IS is a great way to extend its functionality, but getting it to work requires attention to OSGi bundle management, package imports, and debugging techniques.

💡 Pro Tip: If your handler doesn’t work, always check:

  • JAR deployment
  • OSGi bundle status
  • WSO2 logs

Hope this guide helps you avoid the pitfalls I encountered. Happy coding! 🚀

[1] https://is.docs.wso2.com/en/latest/references/extend/user-mgt/write-a-custom-event-handler/

--

--

Achini Udari Jayasena
Achini Udari Jayasena

Written by Achini Udari Jayasena

🌟 With over 8 years in IT, I'm Senior Software Quality Engineer, dedicated to delivering excellence. Let's build exceptional software experiences together

No responses yet