Font Size:

Multi Factor Authentication Plugin

Usages

This is a new feature in Joget DX 9.

Before we get into the Joget MFA API, it is important to define a few terminologies that will be used during the plugin development:

Terminology

Definition

Login Template

The MFA plugin's defined HTML template that is shown to the user to authenticate after entering the correct username and password in the login screen.

Register Template

The MFA plugin’s defined HTML template that is shown to the user to register the specific MFA in the user profile page.

The Joget MFA API provides interfaces and abstract classes for you to develop your IdP plugin with great flexibility.

Plugin Development

To develop an IdP or MFA plugin, there are a few prerequisites:

  • Set up Joget source code and build Joget from scratch: Joget Open Source - Knowledge Base for DX 9

  • Be on the latest commit in the 9.0-RELEASE or 9.0-SNAPSHOT branch in both the jw-community and joget-enterprise repositories. Make sure that Joget is built at least once on this branch.

  • Be familiar with the identity provider or MFA service and any libraries you will use.

  • Have basic Java and web development knowledge for the task.

  • Using an IDE such as IntelliJ or NetBeans is optional, but recommended to ease development.

Interface Classes

The interface classes are the base of the MFA Plugin. They define the methods that must be implemented in order for the plugin to integrate properly with the Joget MFA API. Interface classes are so-called “barebones” and require defining all the methods and properties from scratch. However, they allow for great flexibility and customisation. Currently, there is only one interface: MfaPlugin.

MfaPlugin

org.joget.directory.model.mfa.MfaPlugin

  • Implement all methods for MfaPlugin as defined in the Public API.

  • Implement the required methods in ExtDefaultPlugin and PropertyEditable classes.

  • More details on Joget’s Plugin Framework: Plugin Base Abstract Class and Interface.

  • Extend the ExtDefaultPlugin class to be recognized as a plugin and implement its methods.

Interface Methods

login
boolean login(String username, String data, String secret) throws MfaExecutionException

Processes the MFA login request by handling delegation from MfaManager.

Returns true if the plugin determines that the MFA request is valid, false if it fails.

This method may throw MfaExecutionException if the processing fails, such as invalid data, secret, etc.

  • The exception message will be shown in a banner above the MFA login page.

register

public java.lang.String register(String username, String data) throws MfaExecutionException

Processes MFA registration request by handling delegation from MfaManager.

Returns a String representation of the MFA secret that is associated with the username to be saved to the database for future login calls.

This method may throw MfaExecutionException if the processing fails, such as invalid data, secret, etc.

  • The exception message will be shown in a banner above the MFA login page.

getDisplayName

public java.lang.String getDisplayName()

Gets the (friendly) display name of the plugin. Shown in MFA list and user profile.
 
getLoginTemplate

public java.lang.String getLoginTemplate(String username, HttpServletRequest request) throws MfaExecutionException

Get the login HTML of this plugin to be shown to the user.
 
getRegisterTemplate
public java.lang.String getRegisterTemplate(String username, HttpServletRequest request)throws MfaExecutionException
Get the register HTML of this plugin to be shown to the user.
 

MfaManager

org.joget.directory.model.service.MfaManager

The MfaManager interface provides methods for managing multi-factor authentication (MFA) operations, including login, registration, and unlinking.

Interface Methods

login

boolean login(String pluginClassName, String username, String data) throws ClassNotFoundException, MfaExecutionException

Handles delegating MFA login verification to the specified plugin.

Returns true if the MFA verification from the delegated plugin is successful, false if it fails.

This method may throw ClassNotFoundException if the plugin class name provided is invalid.

This method may throw MfaExecutionException if the processing fails, such as invalid data, secret, etc.

  • The exception message will be shown in a banner above the MFA login page.

register

boolean register(String pluginClassName, String username, String data) throws ClassNotFoundException, MfaExecutionException

Handles delegating MFA register verification to the specified plugin.

Returns true if the MFA registration from the delegated plugin is successful, false if it fails.

This method may throw ClassNotFoundException if the plugin class name provided is invalid.

This method may throw MfaExecutionException if the processing fails, such as invalid data, secret, etc.

  • The exception message will be shown in a banner above the MFA login page.

boolean unlink(String pluginClassName, String username)

Unlinks the specified plugin from the username.

Returns true if unlinking is successful, false if it fails.

isMfaRequired

boolean isMfaRequired(String username)

Returns true if the specified user requires MFA authentication, false if the user does not require MFA authentication or does not have any MFA methods registered.

getMfaLoginLandingPage

String getMfaLoginLandingPage(String username);

Returns the path to the MFA authentication page for the user.

This page could be a landing page that displays the list of registered MFA methods of the user, or a direct page to an MFA authentication page if the user only has a single MFA method registered.

getProfileFooterHtml

String getProfileFooterHtml(User user);

Returns HTML for profile settings.

Abstract Classes

Abstract classes are recommended for starters. It is opinionated and comes with property/configuration values for your plugin (provided below), which allow for a quick and easy way to develop the IdP plugin. The provided methods and property configurations can always be overridden or modified if they do not suit the requirements of the plugin. Currently, there is only one abstract class: AbstractMfaPlugin.

As currently there are no major differences between the interface class and the abstract class, both classes can be used to develop a plugin with similar development time and effort. However, it is still recommended to extend the AbstractMfaPlugin class for a full package, as this class already extends ExtDefaultPlugin and implements MfaPlugin.

AbstractMfaPlugin

org.joget.directory.model.mfa.AbstractMfaPlugin

The AbstractMfaPlugin class extends ExtDefaultPlugin and implements MfaPlugin, providing default implementations for key MFA-related methods.

Abstract Methods

getLabel

String getLabel();

  • Returns the name of the plugin as its label.

getDisplayName

String getDisplayName();

  • Returns the name of the plugin as its display name, used in MFA lists and user profiles.
getClassName

String getClassName();

  • Retrieves the class name using IdpMfaUtil.getClassName(this).

Development Prerequisites

Generate Plugin Template

Generate a plugin template following this KB article: Guideline for Developing a Plugin - Knowledge Base for DX 8.

All MFA plugins require HttpServletRequest, and by default, the generated pom.xml file has excluded the javax.servlet-api package, therefore, we will have to re-include it.

Locate the part of the file where it has these lines:

<!-- Change plugin specific dependencies here -->


<!-- End change plugin specific dependencies here -->
Markup
Copy
 

Add the following lines between the two lines above:

<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.4</version>
</dependency>
Markup
Copy
 

This should be the final result:

<!-- Change plugin specific dependencies here -->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.4</version>
</dependency>
<!-- End change plugin specific dependencies here -->
Markup
Copy
 

Create an MFA class

To integrate the plugin with the Joget MFA API, the plugin requires a class that extends one of the two MFA interfaces/classes mentioned previously. This will allow the plugin to be detected by the MFA Manager and be included in the settings page when the plugin is uploaded to the Joget server.

After creating the class that extends one of the four IdP interfaces/classes, implement the required methods. If you are using an IDE, it should warn you about the methods necessary to implement. If not, please refer to the Public API documentation and the base class’s source code for more information on any additional methods to implement.

Please note that, depending on whether you choose to implement the interface or abstract class, you will have to follow the steps listed:

  • AbstractMfaPlugin:
  • MfaPlugin:
    • Implement all the methods for MfaPlugin as defined in the Public API.
    • Implement the required methods in the ExtDefaultPlugin and PropertyEditable classes.
    • Read more about Joget’s Plugin Framework (ExtDefaultPlugin and PropertyEditable): Plugin Base Abstract Class and Interface - Knowledge Base for DX 9.
    • Extend the ExtDefaultPlugin class to be recognized as a plugin and implement its methods.

Then, in the Activator class, add the following line to register this plugin with Joget’s Plugin Manager, where <class_name> is the name of the class created:

registrationList.add(context.registerService(<class_name>.class.getName(), new <class_name>(), null));
Java
Copy
 

Required Files

Property JSON

A property JSON file is required, which provides the definitions for the plugin configuration. For more information, refer here: Plugin Properties Options - Knowledge Base for DX 9. To add a property JSON file to the plugin, create a directory structure as such,

[Plugin Directory]/src/main/resources/properties

and create a .json file with any name.

As mentioned before, there are currently no differences between the interface and the abstract classes, therefore, there are no specific properties required in the JSON file.

Login and Register Templates

A login and register template is required for every MFA plugin and is served when the login and register methods are called respectively. The template file is a FreeMarker (.ftl) template, more information can be found here: Apache FreeMarker.

Depending on the MFA flow/process, the plugin might require a separate template file for both login and register calls, or, depending on the authentication flow, may share a single template file for both. Therefore, it is recommended to understand the requirements of the MFA flow/process before developing the plugin.

To add a template file to the plugin, create a directory structure as such,

[Plugin Directory]/src/main/resources/templates

and create an .ftl file with any name.

Once the template file is created, in the getLoginTemplate and getRegisterTemplate methods, add the following lines, where <template_file> is the name of the template file to be rendered when the method is called:

PluginManager pluginManager = (PluginManager) AppUtil.getApplicationContext().getBean("pluginManager");



return pluginManager.getPluginFreeMarkerTemplate(new HashMap<>(), getClassName(), "/templates/<template_file>.ftl", null);
Markup
Copy

The HashMap object maps a String key to an Object value and is used to pass objects (such as strings, arrays, etc.) as data to the template so that they can be used in the template. The data can be accessed in the template file using the keys defined in the HashMap. Please check the documentation for Apache FreeMarker for tutorials and how-tos.

Conclusion

Finally, you should now be able to implement the plugin and integrate it with the MFA service/third-party library of your choice.

Here is a short recap of the steps to create an MFA plugin:

  1. Generate a normal Joget plugin following step 6 in this KB article: Guideline for Developing a Plugin - Knowledge Base for DX 9.

  2. Identify which Interface/Abstract class your plugin would implement/extend, and create the Plugin class.

  3. Register the newly created plugin class in the Activator.java file.

  4. Create the JSON property file and ensure that the right template is used depending on the base class the plugin extends.

  5. Create the Login and Register templates using Apache FreeMarker.

  6. Implement the plugin logic, compile, and install it.

Created by Debanraj Last modified by Debanraj on May 29, 2025