On this page
The OAuth Customization using Plugins tutorial explains the base development and deployment setup when working with plugins. Many plugins are relatively straightforward to develop, yet authentication plugins are more intricate, since they deal with frontend concerns like forms, user experience and navigation, and also backend concerns like account data, custom logic and proof validation.
When getting started with plugins, you first need to understand the following foundational techniques:
- How to create HTTP GET and POST endpoints used by login forms.
- How to create frontend forms for both browser-based and native login flows.
- How to collect data client-side, validate it server-side, and integrate custom data.
- How to manage navigation and session state during an authentication workflow.
Once you understand these core behaviors you will be well placed to develop any kind of custom authentication solution. You can also incorporate additional techniques from Curity's GitHub repositories. You use Kotlin or Java to develop an authentication plugin, but you do not need to be an expert in those technologies.
Wizard-Based Example
To explain the concepts, this tutorial uses a wizard-based authenticator. Some online authorities use this type of login user experience, to capture multiple proofs of the user identity one stage at a time. The wizard runs during an OpenID Connect code flow and presents a number of screens. First, a user credentials login form
prompts the user to provide an account ID and password:

Next, a user details login form
prompts the user for further proof of their identity. The user must provide their social security number and date of birth, to be verified using details stored against the user's account.

If required, you could add extra forms, like those that prove ownership of an email or phone. You could do so using SDK objects that send the user email or text (SMS) messages.
Finally, once the user has successfully proven their identity, a success login form
is displayed, as an example of completing a wizard-based login user experience. Authentication completes when the user clicks the Continue button:

If you configure user consent for the client, the user interacts with consent screens, after which the client receives an authorization response. The client can then complete the code flow to get access tokens and send them to its APIs.
Designing Authentication Workflows
Usually, a better approach is to compose authenticators and authentication actions. This tutorial uses a wizard-based approach to teach navigation and demonstrate that an authenticator is not limited to a single form.
Code Layout
The following command generated the files for the initial Kotlin classes for this tutorial:
mvn -B archetype:generate \-DarchetypeArtifactId=identityserver.plugins.archetypes.kotlin-authenticator \-DarchetypeGroupId=io.curity \-DarchetypeVersion=3.0.0 \-DartifactId=example-authenticator \-DgroupId=com.example.plugins.exampleauthenticator \-DpluginName=Example \-Dversion=1.0.0-SNAPSHOT
The mvn archetype
command produces the following Kotlin classes, which are the minimal files needed to develop an authenticator. By default there is no user interface, since an authenticator does not always need one.
├── authentication│ ├── ExampleAuthenticatorRequestHandler.kt│ ├── RequestModel├── config│ │ └── ExampleAuthenticatorPluginConfig.kt├── descriptor│ │ └── ExampleAuthenticatorPluginDescriptor.kt
Each authenticator can have multiple functional areas like authentication, account recovery and user registration. Each area's implementation can use multiple forms. The example authenticator only requires authentication behavior and uses an authentication wizard with three forms:
- The user credentials login form, where the account ID and password are entered
- The user details login form, where the social security number and date of birth are entered
- The success login form, that completes the authentication wizard
The example authenticator's file layout is therefore customized to use three forms and the following source files:
├── authenticate│ ├── handlers│ │ └── UserCredentialsRequestHandler.kt│ │ └── UserDetailsRequestHandler.kt│ │ └── SuccessRequestHandler.kt│ ├── models│ │ └── UserCredentialsRequestModel.kt│ │ └── UserDetailsRequestModel.kt│ │ └── SuccessRequestModel.kt│ ├── representations