How to Write a Custom Event Handler in WSO2 Identity Server (With Debugging Tips)
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/