Font Size:

Identity Provider Plugin

Usages

This is a new feature in Joget DX 9.

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

Terminology

Definition

Authorization Endpoint URL

The external identity provider’s URL, where Joget will redirect the user to for authentication.

Callback URL

Joget’s internal URL for the external identity provider to call back to transfer authorisation credentials.

This URL will be automatically generated by Joget and displayed when you configure the plugin.

It is typically a requirement by your external identity provider to know where to pass the authorisation credentials back to Joget.

User Provisioning

A policy that is checked by the Joget IdP manager and configurable on a per-plugin basis.

This policy determines whether a new user account should be created in Joget if it does not exist.

This policy checks based on the email address of the Joget user and the IdP user.

Automatic Linking

A policy that is checked by the Joget IdP manager and configurable on a per-plugin basis.

This policy determines whether a Joget user should be automatically linked to an IdP user if their email matches.

If enabled, this policy will link if and only if there is one Joget user with the same email as the IdP user. In other words, if there are multiple Joget users sharing the same email, this policy will not link any user.

As an additional security precaution, when automatic linking is enabled, no user who shares the same email is allowed to be logged in via IdP.

Multi-instance IdP plugin

Multi-instance IdP plugins are useful for developing a single plugin to be used for different external identity providers.

Multi-instancing allows system administrators to have different configurations without developing a new plugin for each identity provider.

In other use cases, there might be a single IdP but different requirements for IdP access. Such as different authorisation scopes.

Custom managed IdP plugin

Custom managed IdP plugins are useful for developing a plugin that manages multiple “sub-IDs” in it.

An example plugin that might implement this interface is a passkeys IdP plugin, which allows each user to register multiple passkeys under one IdP plugin.

 

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

Plugin Development

To develop an IdP 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 IdP Plugin. They define the methods that must be implemented in order for the plugin to integrate properly with the Joget IdP 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.

IdentityProviderManager

org.joget.directory.model.service.IdentityProviderManager

Used for plugins that allow only one instance.

Interface Methods

Session Key

public java.lang.String LOGGED_IN_IDP_SESSION_KEY = "LOGGED_IN_IDP"

This session key can be used to determine whether the current session was logged in using an IdP.
If it is logged in using IdP, the session value should be set to the UUID of the IdP that was used to log in; else, it should not be set (i.e., null).

login

boolean login(String username, HttpServletRequest request, String secret);

Performs authentication using Multi-Factor Authentication (MFA). Returns true if verification is successful. Returns false in case of an error.

handleCallback

boolean handleCallback(String pluginUuid, HttpServletRequest callbackRequest)

Handles the callback from the IdP.
The callback is received from the Spring web controller, and the request is delegated to the specified plugin based on its UUID.

getConfiguredIdentityProviderPlugins

Collection<IdentityProviderPlugin> getConfiguredIdentityProviderPlugins()

Returns a list of IdPs that are installed and configured.
This method will always return Plugin objects that are of type IdentityProviderPlugin.

getLoginFooterHtml

public java.lang.String getLoginFooterHtml()

  • Returns HTML content for the login footer.
getProfileFooterHtml

public java.lang.String getProfileFooterHtml(User user)

Returns HTML for the login buttons.

logout

void logout(String pluginUuid, HttpSession session)

Logs out the user from an IdP.
Support for Single Log Out (SLO) is handled by the IdP plugin by implementing the IdentityProviderPlugin.onLogout(HttpSession) method.

IdentityProviderPlugin

org.joget.directory.model.idp.IdentityProviderPlugin

The IdentityProviderPlugin interface extends Plugin and PropertyEditable, providing core functionality for managing authentication via identity providers.

Interface Methods

getUuid

public java.lang.String getUuid();

Returns the UUID of this plugin instance.

setUuid

void setUuid(String uuid);

Sets the UUID of this plugin instance.

handleCallback

User handleCallback(HttpServletRequest callbackRequest);

Handles callback delegation from IdentityProviderManager.
If the plugin determines that a user can be logged in, the returned user object should contain all the necessary information required to provision the user.
This method should return null if the plugin determines that no user should be logged in.
If the IdP supports Single Log Out (SLO) functionality, any data required to log the user out can be stored in the session the callbackRequest parameter using HttpServletRequest#getSession(). The logout data can be accessed later in onLogout(HttpSession).
Please note that the object to be stored in the session must implement the java.io.Serializable interface so that it can be synchronized to other app servers in a scaled/distributed environment.

getAuthorizationEndpoint

public java.lang.String getAuthorizationEndpoint();

Returns the IdP’s authorization endpoint URL.
Authorization endpoint is also known as the login page of the IdP.

isUserProvisioningEnabled

boolean isUserProvisioningEnabled();

Returns the status of the user provisioning policy.
This policy determines if a user should be automatically created when the claimed user does not exist in Joget's directory manager or if this IdP is not linked to any existing user.
User provisioning can only be enabled if Joget is using a directory manager that can be modified by Joget.
Directory managers, such as the default LDAP implementation, cannot be used as Joget is unable to modify the directory.

isProvisionedUserProfileEditable

boolean isProvisionedUserProfileEditable();

Returns whether the provisioned user’s profile should be editable.
Note: This setting only affects newly provisioned users. Previously provisioned users WILL NOT be affected.

isAutomaticLinkingEnabled

boolean isAutomaticLinkingEnabled();

Returns the status of automatic linking policy.
This policy determines if the IdP should be automatically linked to the user when the following criteria is true:
Claimed email equals only one Joget user's email in directory manager.

getLoginButtonTemplate

IdpLoginButtonTemplate getLoginButtonTemplate();

Get the template used for the login button on the login screen.

boolean onUnlink(String username, HttpServletRequest request) throws IdpPluginUnlinkException;

Handle custom unlinking user events.
This method should return true if no custom unlinking is required.
This method will be called first before the Identity Provider Manager executes its own unlink procedure.

onLogout

void onLogout(HttpSession session) throws IdpLogoutException;

Handle custom user logout events. This method is useful for logging out of the IdP when a user logs out of Joget.

MultiInstanceIdentityProviderPlugin

org.joget.directory.model.idp.IdentityProviderPlugin

Used for plugins that support multiple instances.

Interface Method

getConfigurationName

public java.lang.String getConfigName()

Handle custom user logout events. This method is useful for logging out of the IdP when a user logs out of Joget.

CustomManagedIdentityProviderPlugin

org.joget.directory.model.idp.CustomManagedIdentityProviderPlugin

This interface enables an Identity Provider plugin to provide and self-manage "sub-IDs" as well as perform custom logic for validating/verifying their "sub-IDs" on an existing account.

An example plugin that might implement this interface is a passkeys IdP plugin, which allows each user to register multiple passkeys under one IdP plugin. This example plugin will be required to perform its own validation & verification of each user's passkeys via the IdentityProviderPlugin.handleCallback(HttpServletRequest) method. Additionally, user provisioning and automatic linking will be ignored by the Identity Provider Manager.

Identity Provider plugins that implement this interface will have to perform all necessary actions that are originally performed by the Identity Provider Manager, such as:

  • Keeping track of each "sub-ID" and its corresponding user for use during IdP registration and login

  • Handling validation/verification of the "sub-ID" during IdP registration and login

  • Unlinking logic when a user unlinks a "sub-ID" provided by this plugin. See IdentityProviderPlugin.onUnlink(String, HttpServletRequest) for executing custom unlinking logic.

Implementing this interface will change the "Link/Unlink" button for this plugin in the user profile to "Manage". Clicking on this "Manage" button will display a popup which allows the user to perform custom link/unlink procedures defined by the plugin that otherwise cannot be performed with the "Link/Unlink" button

The plugin's managed service UI can be accessed via this URL:

<context_path>/web/idp/<plugin_uuid>/managedService

and subsequently, the URL provided by IdentityProviderPlugin.getAuthorizationEndpoint() will be ignored.

The contents of the pop-up must be controlled by the plugin via the CustomManagedIdentityProviderPlugin.managedService(HttpServletRequest, HttpServletResponse) method. No permissions/limits will be enforced, therefore, it is up to the plugin to perform access control.

Although there are no limitations on this, it is recommended that plugins implementing this interface should not implement MultiInstanceIdentityProviderPlugin or extend any classes that implement that interface, as behaviour is undefined. If implementing said interface is required, additional care should be taken to consider potential edge cases not supported by the existing implementation.

Interface Method

managedService

void managedService(HttpServletRequest request, HttpServletResponse response) throws IOException

This method acts similarly to the PluginWebSupport.webService(HttpServletRequest, HttpServletResponse) method, where the plugin will be able to have full control over the web requests and responses of the endpoint.

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.

AbstractIdentityProviderPlugin

public class AbstractIdentityProviderPlugin

Used for plugins that allow only one instance.

Abstract Methods

GetCallbackUrl

String getCallbackUrl(HttpServletRequest request);

  • Retrieves the callback URL for the identity provider to return authorization tokens.
  • Should be injected into plugin properties to maintain consistency across API updates.
getUuid

public java.lang.String getUuid();

  • Returns the UUID of the identity provider instance.
setUUID

void setUuid(String uuid);

  • Assigns a UUID to the identity provider instance.
getAuthorizationEndpoint

public java.lang.String getAuthorizationEndpoint();

  • Returns the authorization endpoint from plugin properties.
isUserProvisioningEnabled

boolean isUserProvisioningEnabled();

  • Checks if user provisioning is enabled.
isProvisionedUserProfileEditable

boolean isProvisionedUserProfileEditable();

  • Determines if provisioned user profiles are editable.
isAutomaticLinkingEnabled

boolean isAutomaticLinkingEnabled();

  • Checks if automatic user linking is enabled.
getLoginButtonTemplate

IdpLoginButtonTemplate getLoginButtonTemplate();

  • Retrieves the login button template, ensuring relaxed HTML stripping for formatting compatibility.
getLabel

public java.lang.String getLabel();

  • Returns the plugin label, typically the plugin name.
getClassName

public java.lang.String getClassName()

  • Fetches the class name of the identity provider plugin.

boolean onUnlink(String username, HttpServletRequest request) throws IdpPluginUnlinkException;

  • Handles custom unlinking logic for identity provider plugins.
onLogout

void onLogout(HttpSession session) throws IdpLogoutException;

  • Executes logout functionality for identity providers.

AbstractMultiInstanceIdentityProviderPlugin

public class AbstractMultiInstanceIdentityProviderPlugin

It enables multiple instances of an identity provider type to be uniquely identified.

Abstract Method

getConfigName

String getConfigName();

  • Retrieves the configuration name from plugin properties.
  • If no configuration name is set, defaults to the plugin name.

Development Prerequisites

Generate Plugin Template

Generate a plugin template following step 6 in this KB article: Guideline for Developing a Plugin - Knowledge Base for DX 9. Once the plugin template is generated, we will have to modify some parts of the pom.xml file of the plugin.

All IdP 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 them.

 

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 in 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 IdP class

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

After creating the class that extends/implements one of the four IdP interfaces/classes, implement the required methods. If you are using an IDE, it should warn you about the required methods 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:

AbstractIdentityProviderPlugin

org.joget.directory.model.idp.AbstractIdentityProviderPlugin

AbstractMultiInstanceIdentityProviderPlugin

org.joget.directory.model.idp.AbstractIdentityProviderPlugin

IdentityProviderPlugin

org.joget.directory.model.idp.IdentityProviderPlugin

  • Implement all the methods as defined in the Public API.
  • Implement the required methods in the ExtDefaultPlugin and PropertyEditable classes.
  • Read here for more information 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 recognised as a plugin and implement its methods.

MultiInstanceIdentityProviderPlugin

org.joget.directory.model.idp.MultiInstanceIdentityProviderPlugin

  • Implement all the methods as defined in the Public API.
  • Implement the required methods in the ExtDefaultPlugin and PropertyEditable classes.
  • Read here for more information 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 recognised 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));
Markup
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. If the plugin extends the abstract classes, a predefined property definition JSON is required, as the base abstract class has defined several properties.

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.

If the plugin extends AbstractIdentityProviderPlugin You are required to use the template below:

[
  {
    "title": "Configure Plugin",
    "properties": [
      {
        "name": "callbackUrl",
        "label": "Callback URL",
        "type": "label",
        "value": "{{callbackUrl}}",
      },
      {
        "name": "authEndpoint",
        "label": "Authorization Endpoint",
        "type": "textfield",
      },
      {
        "name": "userProvisioning",
        "label": "User Provisioning",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "editableUserProfile",
        "label": "Editable user profile",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "automaticLinking",
        "label": "Automatic Linking",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "loginButtonIconLabel",
        "label": "Login Icon",
        "type": "icon-textfield",
        "required": "true"
      }
    ]
  }
]

JSON
Copy
 

If the plugin extends AbstractMultiInstanceIdentityProviderPlugin, you are required to use the template below:

[
  {
    "title": "Configure Plugin",
    "properties": [
      {
        "name": "callbackUrl",
        "label": "Callback URL",
        "type": "label",
        "value": "{{callbackUrl}}",
      },
      {
        "name": "configName",
        "label": "Configuration Name",
        "type": "textfield",
        "required": "true"
      },
      {
        "name": "authEndpoint",
        "label": "Authorization Endpoint",
        "type": "textfield",
      },
      {
        "name": "userProvisioning",
        "label": "User Provisioning",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "editableUserProfile",
        "label": "Editable user profile",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "automaticLinking",
        "label": "Automatic Linking",
        "type": "checkbox",
        "options": [
          {
            "value": "true",
            "label": "Enabled"
          }
        ]
      },
      {
        "name": "loginButtonIconLabel",
        "label": "Login Icon",
        "type": "icon-textfield",
        "required": "true"
      }
    ]
  }
]

JSON
Copy
 

If the plugin only implements IdentityProviderPlugin, there is no required template to follow. However, please note that if the authentication flow of the plugin requires a callback to the server (such as OAuth 2.0, SAML, etc.), it is required to include the callbackUrl property in the JSON property file. Else, there are no hard requirements for the property JSON file unless the plugin extends the aforementioned abstract classes.

Please make sure the value contains {{callbackUrl}} to ensure the callback URL is properly injected by the IdP framework:

[
  {
    "title": "Configure Plugin",
    "properties": [
      {
        "name": "callbackUrl",
        "label": "Callback URL",
        "type": "label",
        "value": "{{callbackUrl}}",
        "description": "Provide this Callback URL to your Open ID service."
      }
    ]
  }
]
JSON
Copy
 

You are free to add more properties to the property JSON file, but if you would like to remove/modify the values provided above, you must override the methods in the abstract class. However, to reiterate, if you require more flexibility in the options, you should implement the IdentityProviderPlugin interface to customise them.

Next, make sure the getPropertyOptions method returns the following, where <file_name> is the name of the JSON file created:

return AppUtil.readPluginResource(getClass().getName(), "/properties/<file_name>.json", null, true, null);
JSON
Copy

Additional Features

Single Log Out (SLO)

Some identity providers provide the ability for the user on the identity provider side to simultaneously log out when a user logs out on the client (e.g., Joget). This feature is supported by identity provider standards such as OpenID Connect and SAML.

Currently, Joget only supports RP-initiated back-channel logout, whereby Joget will notify the identity provider directly, without a browser, when a user logs out from Joget. As the IdP framework aims to be standard agnostic, every plugin has to implement its own logout procedure.

To implement SLO in your IdP plugin, there are two requirements:

  1. In the IdentityProviderPlugin.handleCallback method, make sure to store any data that is required by the SLO process in the callbackRequest’s session. This can be done by using the setAttribute method from the request’s session, for example:

callbackRequest.getSession().setAttribute("MY_KEY", new MyObject());

  1. Make sure to implement the IdentityProviderPlugin.onLogout method. This method will be responsible for logging out the user on the identity provider’s side. The data that was previously put in the session can be retrieved via the session parameter of the method. Please note that the type information is lost when retrieving session attributes. So it is important to recast it back to its original type, for example:

MyObject myData = (MyObject) session.getAttribute("MY_KEY");

Conclusion

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

Here is a short recap of the steps to create an IdP 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. Implement the plugin logic, compile, and install it.

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