--- title: "Implementing the Secrets plugin" slug: "dpo-api-server-plugin-for-secrets-implementation" updated: 2026-10-27T20:13:12Z published: 2026-10-27T20:13:12Z canonical: "docs.onespan.com/dpo-api-server-plugin-for-secrets-implementation" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.onespan.com/llms.txt > Use this file to discover all available pages before exploring further. # Implementing the Secrets plugin The server components of DigipassONE authentication software use secrets, such as keys and passwords, to access the following external services: - Databases - Push notification services - Private key for APNS (Private Key Operations) - Private key for Firebase Cloud Messaging (Private Key Operations) - App secret for Huawei Messaging Service - Google Play Integrity - Email servers - SMS API (Twilio) - Jumio PhotoID services DigipassONE Server components provide a programmatic interface in Java for you to develop a plugin to retrieve credentials that are managed externally. DigipassONE authentication software allows you to store a password either as a handle to an external secrets manager using your Secrets plugin, or as an encrypted password. ## Creating a Secrets plugin You must implement the following Java interface for a Secrets plugin. Each server component creates a single instance of the class using the no-argument constructor at startup. There may be multiple threads fetching the secrets at the same time. ```java package com.noknok.secrets.spi; /** * Implement this interface to fetch passwords from a password vault   * * The implementation class name should be provided as Java system property * nnl.secrets.plugin.class.name */ public interface SecretsPlugin {    /**     * Called when a password is required by the relevant service. It     * may be called from multiple threads. Implementation can throw an     * RuntimeException if it is unable to fetch a password from the vault     *     * @param context context for the request     * @param secretHandle   Handle that is configured for the password       * @return The actual password from the vault     */    public String fetchSecret(SecretsContext context, String secretHandle); } /** * This class defines the context, in other words, the name of the server property * that represents a password. For example, mail.smtp.password and tenant ID. */ public class SecretsContext {    public SecretsContext(String name, String tenantId);    /**     * Returns the name of the context     *     * @return the name, e.g. "db.password", "mail.smtp.password",     *    "clientSecret"     */    public String getName();    /**     * Returns the id of the tenant     *     * @return the tenant ID, e.g., "Admin"     */    public String getTenantId(); } ``` ## Building the Secrets plugin Follow these guidelines to implement your Secrets plugin: 1. Make sure you have access to a DigipassONE Server installation for development and testing purposes. 2. Build your class that implements the SecretsPlugin interface with a dependency on nnl-secrets-spi-8.0.1-13.jar found inside the folder: /admin/lib/thirdparty. 3. Package your plugin implementation into a jar file. ## Configuring the DigipassONE Server to use the Secrets Plugin **Step 1**. Place a copy of the Secrets plugin implementation jar file, along with its third party dependencies, into all of the following directories: - tomcat/webapps/nnl/WEB-INF/lib/ - tomcat/webapps/nnlgateway/WEB-INF/lib/ - tomcat/webapps/nnladmin/WEB-INF/lib/ - tomcat/webapps/nnlauthsvc/WEB-INF/lib/ - tomcat/webapps/gwtutorial/WEB-INF/lib/ - /admin/lib/thirdparty/ **Step 2**. Assign the implementation class name to the environment variable NNL_SECRETS_PLUGIN_CLASS_NAME for the following components: 1. **Tomcat:** Inside the /bin/setenv.sh file, configure the plugin class name as in the example below: ```plaintext export NNL_SECRETS_PLUGIN_CLASS_NAME=com.mycompany.SecretsPlugin ``` 1. **Command-line utility**: In the terminal where you run the DigipassONE command-line utility, set the environment variable NNL_SECRETS_PLUGIN_CLASS_NAME as in the example below: ```plaintext export NNL_SECRETS_PLUGIN_CLASS_NAME=com.mycompany.SecretsPlugin ``` **Step 3**. Optional. Configure handles for passwords. Note that when you implement a Secrets plugin, the administrator enters a handle to the password that is stored in the external secrets manager. But the administrator also has the option of storing passwords in the database in encrypted form. 1. For Tomcat web apps, edit tomcat/bin/setenv.sh and modify the environment variables to use your handles. Prefix {handle} to handles. For example, if the handle is password_handle, then set the value of the environment variable to {handle}password_handle. ```plaintext export RUNTIME_DB_ENCRYPTED_PASSWORD={handle} ``` 1. For the command-line tool, go to /admin/conf and manually update the files nnl-db.properties and application.properties. Configure the operational database password to be the *handle* with {handle} prefixed to the password. 2. Configure the aliases that work throughout the DigipassONE Server, and ensure password rotation can be accomplished for different services. For the Authentication Server and the Admin Console web apps, the database password is fetched only once from the external secrets manager - on server startup. For command-line operations, the database password is fetched each time you run a command. Database password rotation requires a server restart so that the new password can be fetched using the same handle. If your company requires a new handle then please [contact OneSpan Customer Support](mailto:support@onespan.com). The table below shows the system-wide password that is fetched from the external secrets manager when using a handle. The class SecretsContext is defined in your Secrets plugin source code. | **Password from external secrets manager for** | **SecretsContext** | | --- | --- | | Operational Database | name = db.password tenantId = SYSTEM | 1. Configure tenant-specific handles by using either the Admin Console or the command-line tool nnl-mgmt.sh. If you use the command-line tool, use the properties set command and prefix the literal "{handle}" to the handle from the external secrets manager. If for some service a handle is not available, then use the encrypted password. The two tables below show tenant-specific handles that are fetched from the external secrets manager. The class SecretsContext is defined in your Secrets plugin source code*.* For the services in this first table, the password is fetched from the external secrets manager **once** when the relevant push service is lazy-loaded on the server using the handle configured for the secret. To change your password, use the Admin Console or the command-line tool nnl-mgmt.sh to set the same handle to trigger the server to pick the new password from the external secrets manager. Password rotation does not require restarting the server. | **Password from external secrets manager for** | **SecretsContext** | | --- | --- | | Push notification services | name = ios:##oob.ios.apns.server.cert.password tenantId = your_tenant_id name = ios:##oob.ios.apns.server.token.signing.key tenantId = your_tenant_id name = android:##oob.android.server.key tenantId = your_tenant_id name = android:##oob.hms.service.appsecret tenantId = your_tenant_id | | Private Key for APNS (Private Key Operations) | name = ios:##oob.ios.apns.server.token.signing.key.secret tenantId = your_tenant_id | | Private key for Firebase Cloud Messaging (Private Key Operations) | name = android:##oob.fcm.service.account.key.secret tenantId = your_tenant_id | | JWT Decryption Key for Google Play Integrity | name = ##nnl.play.integrity.jwt.decryption.key tenantId = your_tenant_id | | JWT Verification Key for Google Play Integrity | name = ##nnl.play.integrity.jwt.verification.key tenantId = your_tenant_id | | Service Account Key for Google Play Integrity | name = ##nnl.play.integrity.service.account.key.secret tenantId = your_tenant_id | For the services in this second table, the password is fetched from the external secrets manager each time you call the service for an authentication method-specific secret. Password rotation does not require a server restart if the handle remains the same. | **Password from external secrets manager for** | **SecretsContext** | | --- | --- | | Email Servers | name = mail.smtp.password tenantId = your_tenant_id | | SMS API (Twilio) | name = twilio.auth.token tenantId = your_tenant_id | | Jumio PhotoID services | name = nv.api.secret tenantId = your_tenant_id | If you need to change the handles from either of the above tables, please [contact OneSpan Customer Support](mailto:support@onespan.com). **Step 4**. Verify your Configuration. 1. Restart Tomcat and observe the logs. Verify that the Secrets plugin has been picked up by the runtime system. For example, in the Authenticator Server nnl.log you should see: ```plaintext INFO  [main] com.noknok.secrets.spi.internal.SecretsPluginWrapper loadSecretsPlugin - Secrets plugin implementation configured on the server - com.mycompany.SecretsPlugin ``` 1. Perform an authentication with FIDO OOB that uses push notifications, Email OTP, SMS OTP, and Photo ID. These operations fetch passwords from the external secrets manager. If the Secrets plugin is implemented and configured properly, these operations complete successfully. Read on for installation instructions for your Secrets plugin in a DigipassONE Server for production purposes. Formerly Digipass S3 software. Formerly known as Digipass S3 Server. Formerly known as Digipass S3.