---
title: Action class
description: The Node class returns an Action instance from its process() method.
component: pingam
version: 7.4
page_id: pingam:auth-nodes:core-action
canonical_url: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-action.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
keywords: ["Extensibility", "Nodes &amp; Trees", "Scripts"]
superseded_by: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-action.html
section_ids:
  action_fields_and_methods: Action fields and methods
  accessing-tree-state: Store values in shared tree state
  store-values-in-transient-state: Store values in a tree's node states
  set-get-values-in-tree-state: Get and set values stored in tree state
  set-values-in-tree-state: Set values in the tree state
  get-values-from-tree-state: Get values in the tree state
  accessing-user-profile: Access an identity's profile
  read_an_identitys_profile: Read an identity's profile
  read_attributes_of_an_identitys_profile: Read attributes of an identity's profile
  write_a_value_into_an_identitys_profile: Write a value into an identity's profile
  node-callbacks: Include callbacks
  client-side-javascript: Send and execute JavaScript in a callback
  revisiting-a-node: Handle multiple visits to the same node
---

# Action class

The `Node` class returns an `Action` instance from its `process()` method.

The `Action` class encapsulates changes to authentication tree state and flow control.

For example, the following implementation demonstrates an authentication level decision:

```java
@Override
public Action process(TreeContext context) throws NodeProcessException {
  NodeState state = context.getStateFor(this);
  if (!state.isDefined(AUTH_LEVEL)) {
    throw new NodeProcessException("Auth level is required");
  }
  JsonValue authLevel = state.get(AUTH_LEVEL);
  boolean authLevelSufficient =
    !authLevel.isNull()
    && authLevel.asInteger() >= config.authLevelRequirement();
  return goTo(authLevelSufficient).build();
}
```

For more information, refer to the [Action](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Action.html) class in the *AM Public API Javadoc*.

## Action fields and methods

The `Action` class uses the following fields:

| Fields                             | Description                                                                                                                                                                                                                                                                                                                                                                                             |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `callbacks`                        | A list of the callbacks requested by the node. This list may be `null`.                                                                                                                                                                                                                                                                                                                                 |
| `errorMessage`                     | A custom error message string included in the response JSON if the authentication tree reaches the [Failure node](https://docs.pingidentity.com/auth-node-ref/7.4/failure.html) authentication node.Each node in a tree can replace or update the error message string as the user traverses through the authentication tree.If required, your custom node or custom UI must localize the error string. |
| `lockoutMessage`                   | A custom lockout message string included in the response JSON when the user is locked out.If required, your custom node or custom UI must localize the error string.                                                                                                                                                                                                                                    |
| `outcome`                          | The result of the node.                                                                                                                                                                                                                                                                                                                                                                                 |
| `returnProperties`                 | A map of properties returned to the client.Use `withReturnProperty(String key, Object value)` to add a property to the map.                                                                                                                                                                                                                                                                             |
| `sessionHooks`                     | The list of classes implementing the TreeHook interface that run after a successful login.                                                                                                                                                                                                                                                                                                              |
| `sessionProperties`                | A map of properties added to the final session if the authentication tree completes successfully.Use `putSessionProperty(String key, String value)` and `removeSessionProperty(String key)` to add or remove entries from the map.                                                                                                                                                                      |
| `sharedState` and `transientState` | State that AM shares between nodes through the tree context—the properties set so far by nodes in the tree.Refer to [Store values in shared tree state](#accessing-tree-state).                                                                                                                                                                                                                         |
| `webhooks`                         | The list of webhooks that run after logout.                                                                                                                                                                                                                                                                                                                                                             |

The `Action` class provides the following methods:

| Methods            | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `goTo`             | Specify the exit path to take, and move on to the next node in the tree.For example:```java
return goTo(false).build();
```                                                                                                                                                                                                                                                                                                                                                                                                 |
| `send`             | Send the specified callbacks to the user for them to interact with.For example, the [Username Collector node](https://docs.pingidentity.com/auth-node-ref/7.4/am-only/username-collector.html) uses the following code to send the `NameCallback` callback to the user to request the `USERNAME` value:```java
return send(new NameCallback(bundle.getString("callback.username"))).build();
```                                                                                                                            |
| `sendingCallbacks` | Returns true if the action is a request for input from the user.                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `suspend`          | Suspends the authentication tree, and lets the user resume it from the point it was suspended.For example, the following call is taken from the [Email Suspend node](https://docs.pingidentity.com/auth-node-ref/7.4/email-suspend.html):```java
return suspend(resumeURI -> createSuspendOutcome(context, resumeURI, recipient, templateObject)).build();
```Use the [SuspensionHandler](../_attachments/apidocs/org/forgerock/openam/auth/node/api/SuspensionHandler.html) interface for handling the suspension request. |

The inner class `ActionBuilder` provides the following methods for constructing the `Action` object and setting action-related properties:

| Methods                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addNodeType`                      | Add a node type to the session properties and shared state. Replace any existing shared state with the specified TreeContext's shared state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `addSessionHook` `addSessionHooks` | Add one or more session hook classes for AM to run after a successful login.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `addWebhook` `addWebhooks`         | Add one or more webhook names to the list of webhooks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `build`                            | Creates and returns an Action instance providing the mandatory fields are set.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `putSessionProperty`               | Add a new session property.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `removeSessionProperty`            | Remove the specified session property.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `replaceSharedState`               | Replace the current shared state with the specified shared state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `replaceTransientState`            | Replace the current transient state with the specified transient state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `withErrorMessage`                 | Set a custom message for when the authentication tree reaches the failure node.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `withIdentifiedIdentity`           | Add an identity, authenticated or not, that is confirmed to exist in an identity store. Specify the username and identity type or an `AMIdentity` object.Use this method to record the type of identified user. If the advanced server property, `org.forgerock.am.auth.trees.authenticate.identified.identity` is set to true, AM uses the stored identified identities to decide which user to log in.This lets the authentication tree engine correctly resolve identities that have the same username.For more information, refer to [advanced server properties](../reference/deployment-configuration-reference.html#org.forgerock.am.auth.trees.authenticate.identified.identity). |
| `withLockoutMessage`               | Set a custom message for when the user is locked out.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `withHeader`                       | Set a header for this action.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `withDescription`                  | Set a description for this action.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `withReturnProperty`               | Add a property to the list that is returned to the client.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `withStage`                        | Set a stage name to return to the client to aid the rendering of the UI. The property is only sent if the node also sends callbacks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `withUniversalId`                  | *Deprecated*.Use `withIdentifiedIdentity` instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |

## Store values in shared tree state

Tree state exists for the lifetime of the *authentication session*. Once tree execution is complete, the authentication session is terminated and a *user session* is created. The purpose of tree state is to hold state between the nodes.

A good example is the [Username Collector node](https://docs.pingidentity.com/auth-node-ref/7.4/am-only/username-collector.html), which gets the user name from the user and stores it the shared tree state. Later, the [Data Store Decision node](https://docs.pingidentity.com/auth-node-ref/7.4/data-store-decision.html) can pull this value from shared tree state and use it to authenticate the user.

Authentication sessions when using chains and modules are *stateful* - the AM server that starts the authentication flow must not change. A load balancer cookie is set on the responses to the user to ensure the same AM server is used.

In contrast, authentication trees can be made *stateless*, so that any AM instance in a deployment can continue the authentication session.

For more information on configuring sessions, see [Sessions](../am-sessions/preface.html).

### Store values in a tree's node states

Always store the authentication state in the `NodeState` object that AM lets you access from the `TreeContext` object passed to the node's `action()` method. AM ensures that the node state is made available to downstream nodes:

* Store non-sensitive information with the `NodeState.putShared()` method.

* Store sensitive information, such as passwords, with the `NodeState.putTransient()` method.

  AM encrypts the transient state with the key that has the `am.authn.trees.transientstate.encryption` secret ID. Downstream consumers, such as IDM user self-service nodes, must have the same key to decrypt and read it.

  To ensure that the authentication flow is not bloated with calls to encrypt/decrypt data, and to ensure the authentication session size stays small, limit what you store with `putTransient()`. This is especially true when the realm is configured for client-side authentication sessions.

### Get and set values stored in tree state

Internally, AM distinguishes the following node state data:

* Shared state, where nodes store non-sensitive information that needs to be available during the authentication flow.

  You store this with the `NodeState.putShared()` method.

* Transient state, where nodes store sensitive information that AM encrypts on round trips to the client.

  You store this with the `NodeState.putTransient()` method.

* Secure state, where nodes store decrypted transient state.

For details, see [NodeState](../_attachments/apidocs/org/forgerock/openam/auth/node/api/NodeState.html).

#### Set values in the tree state

To set node state values, get the `NodeState` using the `TreeContext.getStateFor(Node node)` method. Then, use the `NodeState.putShared()` and `NodeState.putTransient()` methods as described above.

For example:

```java
// Setting values in NodeState
public Action process(TreeContext context) {
  String username;
  String password;
  // ...
  NodeState state = context.getStateFor(this);
  state.putShared(USERNAME, username);      // Non-sensitive information
  state.putTransient(PASSWORD, password);   // Sensitive information
  if (!state.isDefined(OPTIONAL_NUMERIC)) { // Check before updating
    state.putShared(OPTIONAL_NUMERIC, 42);
  }
  goToNext().build();
}
```

#### Get values in the tree state

To read node state values, use the `NodeState.ifDefined(String key)` and `NodeState.get(String key)` methods.

For example:

```java
// Getting values from NodeState
public Action process(TreeContext context) {
  NodeState state = context.getStateFor(this);
  String username;
  if (state.isDefined(USERNAME)) {
      username = state.get(USERNAME);
  } else {
    throw new NodeProcessException("Username is required");
  }
  // ...
  goToNext().build();
}
```

The `get(String key)` method retrieves the state for the key from `NodeState` states in the following order:

1. transient

2. secure

3. shared

For example, if the same property is stored in the transient and shared states, the method returns the value of the property in the transient state first.

## Access an identity's profile

AM allows a node to read and write data to and from an identity's profile. This is useful if a node needs to store information more permanently than when using either the authentication trees' `NodeState`, or the identity's session.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Any node which reads or writes to an identity's profile must only occur in a tree after the identity has been verified. For example, as the final step in a tree, or directly after a [Data Store Decision node](https://docs.pingidentity.com/auth-node-ref/7.4/data-store-decision.html).To store a verified identity in the authentication session, call `ActionBuilder.withIdentifiedIdentity()`. This ensures identities with the same username are correctly resolved. |

### Read an identity's profile

Use the `IdUtils` static class:

```java
AMIdentity id = IdUtils.getIdentity(username, realm);
```

|   |                                                                |
| - | -------------------------------------------------------------- |
|   | Wrap the method call in an instantiable class to ease testing. |

If AM is configured to search for the identity's profile using a different search attribute to the default, provide the attributes as a third argument to the method.

To obtain the attributes you could request them in the configuration of the node, or obtain them from the realm's authentication service configuration.

The following example demonstrates how to obtain the user alias:

```java
public AMIdentity getIdentityFromSearchAlias(String username, String realm) {
    ServiceConfigManager mgr = new ServiceConfigManager(
            ISAuthConstants.AUTH_SERVICE_NAME,
            AccessController.doPrivileged(AdminTokenAction.getInstance());

    ServiceConfig serviceConfig = mgr.getOrganizationConfig(realm, null);

    Set<String> realmAliasAttrs = serviceConfig.getAttributes()
        .get(ISAuthConstants.AUTH_ALIAS_ATTR);

   return IdUtils.getIdentity(username, realm, realmAliasAttrs);
}
```

By combining these approaches, you can search for an identity by using the ID and whichever configured attribute field(s) as necessary.

### Read attributes of an identity's profile

After obtaining the profile, use the `AMIdentity#getAttribute(String name)` method.

### Write a value into an identity's profile

Create a `Map<String, Set<String>>` structure of the attributes you wish to write, as follows:

```java
Map<String, Set<String>> attrs = new HashMap<>();
attrs.put("attribute", Collections.singleton("value"));
user.setAttributes(attrs);
user.store();
```

## Include callbacks

Nodes use *callbacks* to enable interaction with the authenticating user.

PingAM doesn't support creating your own custom callbacks, but there are many existing implementations available to you. Learn more in [Supported callbacks](../am-authentication/authn-supported-callbacks.html).

Calling the `getCallbacks(Class<t> callbackType)` method on a `TreeContext` - the sole argument to the `process()` method of a node - returns all callbacks of a particular type for the most recent request from the current node. For example, calling `context.getCallbacks(PasswordCallback.class)` returns a list of the `PasswordCallback` callbacks displayed in the UI most recently.

Below is an example of multiple callbacks created by a node and passed to the UI:

![An example of multiple callbacks created by a node and passed to the UI.](_images/callbacks.png)

To process the responses to callbacks, you must know the order of the callbacks in the list. You can find the position of the callbacks created by the current node by using the constant properties for each callback position in the processing node.

If the callbacks were created in previous nodes, their positions must be stored in the shared state before subsequent nodes can use them.

The following is the code that created the UI displayed in the previous image:

```java
ImmutableList.of(
  new TextOutputCallback(messageType, message.toUpperCase()),
  new PasswordCallback(bundle.getString("oldPasswordCallback"), false),
  new PasswordCallback(bundle.getString("newPasswordCallback"), false),
  new PasswordCallback(bundle.getString("confirmPasswordCallback"), false),
  confirmationCallback
);
```

Note that the order of callbacks defined in code is preserved in the UI.

### Send and execute JavaScript in a callback

A node can provide JavaScript for execution on the client side browser.

For example, the following is a simple JavaScript script named `hello-world.js`:

```java
alert("Hello, World!");
```

Execute the script on the client by using the following code:

```java
String helloScript = getScriptAsString("hello-world.js");
ScriptTextOutputCallback scriptCallback = new ScriptTextOutputCallback(helloScript);
ImmutableList<Callback> callbacks = ImmutableList.of(scriptCallback);
return send(callbacks).build();
```

Variables can be injected using your favorite Java String utilities, such as `String.format(script, myValue)`.

To retrieve the data back from the script, add `HiddenValueCallback` to the list of callbacks sent to the user, as follows:

```java
HiddenValueCallback hiddenValueCallback = new HiddenValueCallback("myHiddenOutcome", "false");
```

The JavaScript needs to add the required data to the `HiddenValueCallback` and submit the form, for example:

```javascript
document.getElementById('myHiddenOutcome').value = "client side data";
document.getElementById("loginButton_0").click();
```

In the process method of the node, retrieve the hidden callback as follows:

```java
Optional<String> result = context.getCallback(HiddenValueCallback.class)
  .map(HiddenValueCallback::getValue)
  .filter(scriptOutput -> !Strings.isNullOrEmpty(scriptOutput));

if (result.isPresent()) {
  String myClientSideData = result.get();
}
```

## Handle multiple visits to the same node

Authentication flow can return to the same decision node by using two different methods.

The first method is to route the failure outcome through a [Retry Limit Decision node](https://docs.pingidentity.com/auth-node-ref/7.4/retry-limit-decision.html). This node can limit how many times a user can enter incorrect authentication details. In these instances, the user is returned to re-enter their information; for example, back to an earlier [Username Collector node](https://docs.pingidentity.com/auth-node-ref/7.4/am-only/username-collector.html).

The second method involves routing directly back to the currently processing node. To achieve this, use the `Action.send()` method, rather than `Action.goTo()`. The `Action.goTo` method passes control onto the next node in the tree. The `Action.send()` method takes a list of callbacks which you can construct in the current node. The return value is an `ActionBuilder`, which can be used to create an `Action`, as follows:

```java
ActionBuilder action = Action.send(ImmutableList.of(new ChoiceCallback(), new ConfirmationCallback()));
```

A typical example of returning to the same node is a password change screen where the user must enter their current password, new password, and new password confirmation. The node that processes these callbacks needs to remain on the screen and display an error message if any of the data entered by the user is incorrect. For example, if the new password and password confirmation do not match.

When a `ConfirmationCallback` is invoked on a screen that was produced by `Action.send()`, it will always route back to the node that created it. Once the details are valid, return an `Action` created using `Action.goTo()` and tree processing can continue as normal.
