Maintaining Authentication Nodes

This chapter covers post-installation tasks relating to authentication nodes, such as testing, debugging, auditing, and performance monitoring.


You can test authentication nodes in numerous ways. For example, you can use unit tests, functional tests, and perform exploratory or manual testing.

Authentication nodes are well suited to tests which have a high percentage of code coverage. The low amount of static dependencies mean that unit testing of the node class itself can occur, rather than simply the business logic classes, as was the case for modules. Furthermore, as nodes should be significantly smaller than modules, testing iterations should be much shorter.

Unit Tests

Your unit tests should aim for an appropriately high level percentage of coverage of the code. Unit testing becomes easier with nodes, as most of the business logic is defined by the tree layout, rather than in the nodes themselves.

At minimum, the process(TreeContext context) method should be tested to ensure that all appropriate code paths are triggered based on the existence, or lack of, appropriate values in the shared state and callbacks.

The TreeContext class and contents have been designed to make sure they are simple to use in unit tests, without the need to resort to mocking.

Functional Tests

Functional tests involve deploying the node into an AM instance and testing it using the authentication REST API. They should be written to cover all normal flows through the node.

All the appropriate code paths discovered through unit testing should be functionally tested to ensure that helper, utility, and related mechanisms function as expected.

Additionally, functional tests will ensure that the business logic is correctly called and processed as expected.


Mocking expected services may be useful when functionally testing nodes that call out to third-party services.

Manual Testing

Manual testing should occur both during and after node development.

During development, it is expected a node developer will frequently load and reload nodes to ensure they operate as expected, including configuration and execution, as well as any expected error conditions.

After development, manual testing should continue in an exploratory fashion. Simply using a node numerous times can often highlight areas left unpolished, or particular usability issues that may be missed by automated testing.


Add debug logging to your custom node to help administrators and support staff investigate any issues which may arise in production.

To add debug logging to a node, obtain a reference to the amAuth SLF4J Logger instance.

For example, you can assign the logger to a private field as follows:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// ...

private final Logger logger = LoggerFactory.getLogger("amAuth");


Consider the logging level you use - over use of the error or warning level can cause debug logs to fill, and even affect performance if your node is used frequently.

You can also use the SLF4J varargs methods to defer string concatenation to SLF4J. This means string concatenation can be skipped if the configured logging level means that your message will not be written.

The following example uses the debug level:

logger.debug("authLevelSufficient {}", authLevelSufficient);


Audit logging helps administrators to investigate user and system behavior.

AM records all incoming calls as access events. Additionally, in order to capture further details regarding authentication flows, AM records an authentication audit event for each node, and the tree outcome.

A node can provide extra data to be included in the standard audit event which is logged when an authentication node completes.

AM logs an AM-NODE-LOGIN-COMPLETED audit event each time an authentication node completes. To add extra information to this audit event, override the node interface method getAuditEntryDetail.

For example, the Retry Limit Decision Node overrides this method to record how many retries remain:

public JsonValue getAuditEntryDetail() {
  return json(object(field("remainingRetries",

When this node is processed, it results in an audit event similar to the following:

  "realm": "/",
  "transactionId": "45453155-cf94-4e23-8ee9-ecdfc9f97e12-1785617",
  "component": "Authentication",
  "entries": [
      "info": {
        "nodeOutcome": "Retry",
        "treeName": "Example",
        "displayName": "Retry Limit Decision",
        "nodeType": "RetryLimitDecisionNode",
        "nodeId": "bf010b6b-61f8-457e-80f3-c3678e5606d2",
        "authLevel": "0",
        "nodeExtraLogging": {
          "remainingRetries": "2"
  "timestamp": "2018-08-24T09:43:55.959Z",
  "trackingIds": [
  "_id": "45453155-cf94-4e23-8ee9-ecdfc9f97e12-1785622"

The result of the getAuditEntryDetail method is stored in the nodeExtraLogging field.


You can track authentication flows which complete with success, failure, or timeout as an outcome by using the metrics functionality built-in to AM. For more information, see Monitoring Instances.

You can also use the following nodes in a tree to create custom metrics:

Read a different version of :