---
title: Metadata annotation
description: "The Metadata annotation specifies two required attributes: the outcomeProvider and the configClass. Typically, the configClass attribute is an inner interface in the node implementation class."
component: pingam
version: 8.1
page_id: pingam:auth-nodes:core-metadata
canonical_url: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-metadata.html
keywords: ["Extensibility", "Nodes &amp; Trees", "Scripts"]
section_ids:
  outcome-provider: Outcome provider
  config-class: Configuration class
  config-validator: Configuration validator
  extensions: Extensions
  tags: Tags
---

# Metadata annotation

The `Metadata` annotation specifies two required attributes: the `outcomeProvider` and the `configClass`. Typically, the `configClass` attribute is an inner interface in the node implementation class.

You can also specify the following optional attributes: `configValidator`, `extensions`, and `tags`.

For example, the following is the `@Node.Metadata` annotation for the [Data Store Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/data-store-decision.html):

```java
@Node.Metadata(outcomeProvider = AbstractDecisionNode.OutcomeProvider.class,
        configClass = DataStoreDecisionNode.Config.class,
        tags = {"basic authn", "basic authentication"})
```

## Outcome provider

The `outcomeProvider` class defines the possible node outcomes.

The abstract implementations of the node interface, `org.forgerock.openam.auth.node.api.SingleOutcomeNode` and `org.forgerock.openam.auth.node.api.AbstractDecisionNode`, define outcome providers you can use for simple use cases. Provide your own implementation for more complex use cases.

To ensure the node is available to the [Configuration Provider node](https://docs.pingidentity.com/auth-node-ref/8.1/config-provider.html), your outcome provider class must implement the `StaticOutcomeProvider` or the `BoundedOutcomeProvider` interfaces.

Learn more about these implementations and interfaces in the [org.forgerock.openam.auth .node.api](../_attachments/apidocs/org/forgerock/openam/auth/node/api/package-summary.html) package.

For example, the following is the custom outcome provider from the [LDAP Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/ldap-decision.html), which has `True`, `False`, `Locked`, `Cancelled`, and `Expired` exit paths:

```java
    /**
     * Defines the possible outcomes from this Ldap node.
     */
    public static class LdapOutcomeProvider implements StaticOutcomeProvider {
        @Override
        public List<Outcome> getOutcomes(PreferredLocales locales) {
            ResourceBundle bundle = locales.getBundleInPreferredLocale(LdapDecisionNode.BUNDLE,
                    LdapOutcomeProvider.class.getClassLoader());
            return ImmutableList.of(
                    new Outcome(LdapOutcome.TRUE.name(), bundle.getString("trueOutcome")),
                    new Outcome(LdapOutcome.FALSE.name(), bundle.getString("falseOutcome")),
                    new Outcome(LdapOutcome.LOCKED.name(), bundle.getString("lockedOutcome")),
                    new Outcome(LdapOutcome.CANCELLED.name(), bundle.getString("cancelledOutcome")),
                    new Outcome(LdapOutcome.EXPIRED.name(), bundle.getString("expiredOutcome")));
        }
    }
```

## Configuration class

The `configClass` contains the configuration of any attributes requested by the node when using it as part of a tree.

Learn more in the [Config interface](core-config.html).

## Configuration validator

The optional `configValidator` class validates the provided configuration at the class level. This can be useful when you have two attributes that depend on each other for validation. For example, an attribute is only required if another attribute is set to `true`.

The `configValidator` class must implement the [ServiceConfigValidator](../_attachments/apidocs/org/forgerock/openam/sm/ServiceConfigValidator.html) interface.

For example, the following is the `@Node.Metadata` annotation for the [Message node](https://docs.pingidentity.com/auth-node-ref/8.1/message.html):

```java
@Node.Metadata(outcomeProvider = AbstractDecisionNode.OutcomeProvider.class,
        configClass = MessageNode.Config.class,
        configValidator = MessageNode.MessageNodeValidator.class,
        tags = {"utilities"})
```

Where the `MessageNode.MessageNodeValidator.class` validates the locales entered:

```java
    /**
     * Validates the message node, ensuring all provided Locales are valid.
     */
    public static class MessageNodeValidator implements ServiceConfigValidator {

        private final Logger logger = LoggerFactory.getLogger(MessageNodeValidator.class);

        private static String getLocaleStringFromMessage(String message) {
            return StringUtils.substringBetween(message, "[", "]");
        }

        @Override
        public void validate(Realm realm, List<String> configPath, Map<String, Set<String>> attributes)
                throws ServiceConfigException, ServiceErrorException {
            for (String messageAttribute : MESSAGE_ATTRIBUTES) {
                validateMessageAttribute(attributes, messageAttribute);
            }
        }

        private void validateMessageAttribute(Map<String, Set<String>> attributes, String messageAttribute)
                throws ServiceConfigException {
            Set<String> attributesSet = attributes.get(messageAttribute);
            Set<Locale> messageLocales = attributesSet.stream()
                    .map(MessageNodeValidator::getLocaleStringFromMessage)
                    .map(com.sun.identity.shared.locale.Locale::getLocale)
                    .collect(Collectors.toSet());
            for (Locale messageLocale : messageLocales) {
                if (!LocaleUtils.isAvailableLocale(messageLocale)) {
                    logger.debug("Invalid messageLocale {} for {} attribute", messageLocale.toString(),
                            messageAttribute);
                    throw new ServiceConfigException("Invalid locale provided");
                }
            }
        }
    }
```

## Extensions

The optional `extensions` class provides additional metadata information about the node. The Java class is serialized into JSON.

For example, the following is the `@Node.Metadata` annotation for the [Username Collector node](https://docs.pingidentity.com/auth-node-ref/8.1/am-only/username-collector.html) with an `extensions` class added:

```java
@Node.Metadata(outcomeProvider = SingleOutcomeNode.OutcomeProvider.class,
        configClass = UsernameCollectorNode.Config.class,
        extensions = UsernameCollectorNode.ExtraMetadata.class,
        tags = {"basic authn", "basic authentication"})
```

Where the `UsernameCollectorNode.ExtraMetadata.class` adds extra metadata:

```java
/**
     * Extra Metadata for the username collector node.
     */
    public static class ExtraMetadata {

        /**
         * The owner of the node.
         */
        public String owner = "Ping Identity";

    }
```

To retrieve the metadata for a node, send a `POST` request to the `realm-config/authentication/authenticationtrees/nodes/node-name/n.0?_action=getType` endpoint.

Example response:

```json
"metadata": {
    "owner": "Ping Identity",
     ...
},
```

## Tags

The optional `tags` attribute contains a list of tags to categorize the node within the tree designer view.

Tags are made up of one or more text strings that let users find the node more easily when designing trees. For example, you could include common pseudonyms for the functionality the node provides, such as `mfa` for a node that provides multi-factor authentication functionality.

The tree designer view organizes nodes into a number of categories, based on the presence of certain tag values, as described in the table below:

**Authentication node tag categories**

| Category             | Tag                      | Example nodes                                                                                                                                                                                                                       |
| -------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Basic Authentication | `"basic authentication"` | [Data Store Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/data-store-decision.html) [Username Collector node](https://docs.pingidentity.com/auth-node-ref/8.1/am-only/username-collector.html)                     |
| MFA                  | `"mfa"`                  | [Push Sender node](https://docs.pingidentity.com/auth-node-ref/8.1/push-sender.html) [WebAuthn Authentication node](https://docs.pingidentity.com/auth-node-ref/8.1/webauthn-authentication.html)                                   |
| Risk                 | `"risk"`                 | [Account Lockout node](https://docs.pingidentity.com/auth-node-ref/8.1/account-lockout.html) [CAPTCHA node](https://docs.pingidentity.com/auth-node-ref/8.1/captcha.html)                                                           |
| Behavioral           | `"behavioral"`           | [Increment Login Count node](https://docs.pingidentity.com/auth-node-ref/8.1/increment-login-count.html) [Login Count Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/login-count-decision.html)                     |
| Contextual           | `"contextual"`           | [Cookie Presence Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/cookie-presence-decision.html) [Set Persistent Cookie node](https://docs.pingidentity.com/auth-node-ref/8.1/set-persistent-cookie.html)             |
| Federation           | `"federation"`           | [OAuth 2.0 node](https://docs.pingidentity.com/auth-node-ref/8.1/am-only/oauth2.html) [OpenID Connect node](https://docs.pingidentity.com/auth-node-ref/8.1/am-only/oidc.html)                                                      |
| Identity Management  | `"identity management"`  | [Anonymous User Mapping node](https://docs.pingidentity.com/auth-node-ref/8.1/anonymous-user-mapping.html) [Terms and Conditions Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/terms-and-conditions-decision.html) |
| Utilities            | `"utilities"`            | [Choice Collector node](https://docs.pingidentity.com/auth-node-ref/8.1/choice-collector.html) [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/scripted-decision.html)                                     |

|   |                                                                                                               |
| - | ------------------------------------------------------------------------------------------------------------- |
|   | Nodes that aren't tagged with one of these tags appear in an **[icon: square, set=fa]Uncategorized** section. |

For example, the `@Node.Metadata` annotation for [Timer Start node](https://docs.pingidentity.com/auth-node-ref/8.1/timer-start.html) places it in the Utilities section:

```java
@Node.Metadata(outcomeProvider = SingleOutcomeNode.OutcomeProvider.class,
        configClass = TimerStartNode.Config.class,
        tags = {"metrics", "utilities"})
```

Learn more in the [Annotation Interface Node.Metadata](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Node.Metadata.html).

To retrieve the tags for a node, send a `POST` request to the `realm-config/authentication/authenticationtrees/nodes/node-name/n.0?_action=getType` endpoint.

Example response:

```json
"tags": [
    "metrics",
    "utilities"
],
```
