---
title: Config interface
description: The Config interface of a node contains the configuration values required by a particular node instance.
component: pingam
version: 7.2
page_id: pingam:auth-nodes:core-config
canonical_url: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-config.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
superseded_by: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-config.html
section_ids:
  sharing-node-config: Share configuration between nodes
  creating-shared-aux-service: Create a shared auxiliary service
  referencing-shared-aux-service: Reference a shared auxiliary service instance
  reinstall-shared-aux-service: Reinstall a shared auxiliary service instance
  allowing-multiple-aux-service-instances: Allow multiple instances of an auxiliary service
  referencing-am-configs: Get configuration of built-in services
  referencing-am-configs-annotated: Get configuration from an annotated service
  referencing-am-configs-legacy: Get configuration from a legacy service
---

# Config interface

The `Config` interface of a node contains the configuration values required by a particular node instance.

Note that you do not need to write a class that implements the interface you define, AM will create it automatically, as required.

Define the properties the node will use in the `Config` interface, by using the `@Attribute` annotation. The `@Attribute` annotation specifies the order of the properties in the tree designer view as well as providing a way to specify additional validators.

Example:

```none
public interface Config {
    @Attribute(order = 1)
    String domain(); (1)

    @Attribute(order = 2, validators = RequiredValueValidator.class)
    boolean isVerificationRequired(); (2)

    @Attribute(order = 3, validators = RequiredValueValidator.class)
    @Password
    char[] clientSecret(); (3)

    @Attribute(order = 4)
    default YourCustomEnum action() {
        return YourCustomEnum.LockScreen; (4)
    };
}
```

|       |                                                                                                                                                                                                                                                  |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **1** | The `domain` attribute is a string-typed value which can be provided in the tree designer view by the tree administrator. It can be read in the `process` method by using a reference to the `config` interface; for example, `config.domain()`. |
| **2** | A boolean attribute with an additional parameter, `validators`, containing a reference to a validation class. In this case, a value is required to be provided by the tree administrator.                                                        |
| **3** | Use the [Password](../_attachments/apidocs/org/forgerock/openam/sm/annotations/adapters/Password.html) annotation to mask the input characters and encrypt the value of the attribute.                                                           |
| **4** | A custom enum attribute. This provides type safety and negates the misuse of Strings as generic type-unsafe value holders. The UI will correctly handle the enum and only let the tree administrator chose from the defined enum values.         |

The defined properties appear as configurable options in the tree designer view when adding a node of the relevant type. For example, the configuration for the [Scripted Decision node](../authentication-guide/auth-node-configuration-hints.html#auth-node-scripted-decision) appears as follows:

![The Scripted Decision authentication node properties.](_images/trees-node-scripted-decision-props.png)

Note that attribute names are used when localizing the node's text, see [Internationalization](i18n-nodes.html).

For more information, see the [Config](../_attachments/apidocs/org/forgerock/openam/annotations/sm/Config.html) annotation type and the [Attribute](../_attachments/apidocs/org/forgerock/openam/annotations/sm/Attribute.html) annotation type in the *AM Public API Javadoc*.

## Share configuration between nodes

You can share configuration between nodes that have common properties. For example, a number of your nodes may call out to an external service that requires a username, password, IP address, and port setting.

Rather than repeat the same configuration in each of these nodes, you can create a shared, auxiliary *service* to hold the common properties in one of your nodes, and reference that service from multiple other nodes.

The following sections explain how to create this auxiliary service and reference it in your nodes. Also covered is how to run more than one instance of an auxiliary service if required, and how to obtain the configuration from services built-in to AM.

### Create a shared auxiliary service

You can create a shared auxiliary service in the configuration interface defined as part of a node. Annotate the service with the `org.forgerock.openam.annotations.sm.Config` annotation to describe how the service functions.

Specify the scope of the service, either `GLOBAL` or `REALM`, as shown below:

```java
@Config(scope = Config.Scope.REALM)
public interface MyAuxService {
   @Attribute(order = 1)
   String serviceUrl();
}
```

You can also specify other features of the service, such as whether the service is a singleton in its scope, or if it can have multiple instances. For information about supporting multiple instances, see [Allow multiple instances of an auxiliary service](#allowing-multiple-aux-service-instances).

### Reference a shared auxiliary service instance

To access the shared auxiliary service, add `org.forgerock.openam.sm.AnnotatedServiceRegistry` to the `@Inject`-annotated constructor of the node.

Obtain the instance using the get instance methods on that class, for example:

```java
serviceRegistry.getRealmSingleton(MyAuxService.class, realm)
```

### Reinstall a shared auxiliary service instance

When developing a custom authentication node that references a shared auxiliary service, it can be useful for the node to be able to remove and reinstall the auxiliary service during upgrade, so that any existing configuration is cleared.

In the `upgrade` function of your plugin class, use the following example code to remove and reinstall a service:

```java
public void upgrade(String fromVersion) throws PluginException {
    SSOToken adminToken = AccessController.doPrivileged(AdminTokenAction.getInstance());
    if (fromVersion.equals(PluginTools.DEVELOPMENT_VERSION)) {
        ServiceManager sm = new ServiceManager(adminToken);
        if (sm.getServiceNames().contains("MyAuxService")) {
            sm.removeService("MyAuxService", "1.0");
        }
        pluginTools.install(MyAuxService.class);
    }
}
```

For more information on upgrading custom authentication nodes, see [Upgrade nodes and change node configuration](node-upgrade.html).

### Allow multiple instances of an auxiliary service

To enable configuration of multiple instances of the auxiliary service in either the same realm or at a global level, set the `collection` attribute to `true` in the `Config` annotation.

You can present the names of the instances of the service as a drop-down menu to the tree administrator.

To be able to present the names, make sure the service instance exposes its `id`, as follows:

```java
@Config(scope = Config.Scope.REALM, collection = true)
public interface MyAuxService {
   @Id
   String id();

   @Attribute(order = 1)
   String serviceUrl();
}
```

Change the nodes that will be using a service instance to store the `id` it uses, and implement `choiceValuesClass` as shown below:

```java
public class MyCustomNode implements Node {
   public interface Config {
       @Attribute(order = 1, choiceValuesClass = ExternalServiceValues.class)
       String serviceId();
   }

   public static class ExternalServiceValues extends ChoiceValues {

       @Override
       public Map<String, String> getChoiceValues() {
           return getChoiceValues(null);
       }

       @Override
       public Map<String, String> getChoiceValues(Map envParams) {
           String realmName = "/";
           if (envParams != null) {
               realmName = (String) envParams.getOrDefault(Constants.ORGANIZATION_NAME, "/");
           }
           try {
               return InjectorHolder.getInstance(AnnotatedServiceRegistry.class)
                       .getRealmInstances(MyAuxService.class, Realms.of(realmName))
                       .stream()
                       .collect(Collectors.toMap(MyAuxService::id, MyAuxService::id));
           } catch (SSOException | SMSException | RealmLookupException e) {
               LoggerFactory.getLogger("amAuth").error("Couldn't load realm {}", realmName, e);
               throw new IllegalStateException("Couldn't load realm that was passed", e);
           }
       }
   }
   // ...
}
```

### Get configuration of built-in services

You can obtain configuration from services built-in to AM. For example, you might want to access the Email Service configuration to obtain the SMTP settings for the realm.

AM services are defined by two methods:

1. Most services are defined by using an annotated interface.

2. Legacy services that are defined by using an XML file.

See the following sections for information on obtaining the configuration from services defined with either of the two methods.

#### Get configuration from an annotated service

To obtain the configuration from a service that uses an annotated interface, add `org.forgerock.openam.sm.AnnotatedServiceRegistry` to your Guice constructor. If the configuration is realm-based, include the realm in the constructor, as follows:

```java
public class MyCustomNode extends SingleOutcomeNode {

   private final AnnotatedServiceRegistry serviceRegistry;
   private final Realm realm;

   @Inject
   public MyCustomNode(@Assisted Realm realm, AnnotatedServiceRegistry serviceRegistry) {
      this.realm = realm;
      this.serviceRegistry = serviceRegistry;
   }
   // ...
}
```

Obtain an instance of the service using one of the get methods of `AnnotatedServiceRegistry` in the constructor.

If the calls you make depend on input from elsewhere in the tree you can add `AnnotatedServiceRegistry` to the `process` method. Note that the following example assumes that a previous node has stored the ID of the AM service to use in shared state:

```java
public Action process(TreeContext context) throws NodeProcessException {
   String serviceId = context.getState.get("myAuxServiceId");
   MyAuxService instance = serviceRegistry.getRealmInstance(MyAuxService.class, realm, serviceId);
   // ...
}
```

#### Get configuration from a legacy service

To obtain an instance of the configuration from a legacy service, use the APIs in the `com.sun.identity.sm` package.

For example, to obtain the configuration values from a *realm* instance of a service, use `ServiceConfigManager` as follows:

```java
ServiceConfigManager scm = new ServiceConfigManager("legacyServiceName", token);
ServiceConfig sc = scm.getOrganizationConfig(realm.asPath(), null);
final Map<String, Set<String>> configMap = sc.getAttributes();
```

However, to obtain the configuration values from a *global* instance of a service, use `ServiceSchemaManager` as follows:

```java
ServiceSchemaManager ssm = new ServiceSchemaManager("legacyServiceName", getAdminToken());
Map<String, Set<String>> configMap = ssm.getGlobalSchema().getAttributeDefaults();
```
