Create tree hooks
Use tree hooks to run custom server-side logic after an authentication tree successfully completes and creates a session. Tree hooks can perform post-authentication tasks, like setting persistent cookies, logging detailed audit events, or adding information to the final response that’s sent to the client.
A hook isn’t a standalone component. You register it from a specific authentication node during the authentication journey. When the tree finishes successfully, AM runs all registered hooks, which lets them act on the new session.
AM includes the following built-in authentication tree hooks:
| Tree hook | Used by node | Details |
|---|---|---|
|
Creates a JWT that contains session, encryption, and node details. The JWT is then used to set a persistent cookie on the response. |
|
|
Adds error details to the response when a tree ends in a failure state. To add error details to the message when the |
|
|
Adds failure details to the response when a tree ends in a failure state. To add failure details to the message when the |
|
|
Adds success details to the response. |
|
|
Recreates the specified persistent cookie with a new idle time and JWT |
Core class of an authentication tree hook
This example shows an excerpt from the UpdatePersistentCookieTreehook class. The Persistent Cookie Decision node uses this tree hook to recreate and refresh a persistent cookie after a successful login.
/**
* A TreeHook for updating a persistent cookie.
*/
@TreeHook.Metadata(configClass = PersistentCookieDecisionNode.Config.class) 1
public class UpdatePersistentCookieTreeHook implements TreeHook { 2
...
@Inject 3
UpdatePersistentCookieTreeHook(@Assisted Request request,
@Assisted Response response,
@Assisted PersistentCookieDecisionNode.Config config,
@Assisted Realm realm,
PersistentJwtStringSupplier persistentJwtStringSupplier,
PersistentCookieResponseHandler persistentCookieResponseHandler,
SecretReferenceCache secretReferenceCache){
this.request = request;
this.response = response;
this.config = config;
this.persistentJwtStringSupplier = persistentJwtStringSupplier;
this.persistentCookieResponseHandler = persistentCookieResponseHandler;
this.secretCache = secretReferenceCache.realm(realm);
}
@Override
public void accept() throws TreeHookException { 4
logger.debug("UpdatePersistentCookieTreeHook.accept");
String orgName = PersistentCookieResponseHandler.getOrgName(response);
Cookie originalJwt = getJwtCookie(request, config.persistentCookieName());
if (originalJwt == null) {
return;
}
// ... Logic to update and set cookie on response
}
//...
}
1 The @TreeHook.Metadata annotation registers the class as a Tree Hook and links it to a configuration class. In this case, it specifies that the hook uses the settings that you define for the PersistentCookieDecisionNode.
2 Your core class must implement the TreeHook interface, which makes sure it has methods like accept() that the authentication framework can call.
Learn more in the TreeHook interface in the AM Public API Javadoc.
3 AM uses the Google Guice framework for dependency injection.
The @Inject annotation on the constructor tells Guice to create a new instance of the hook and provide all required service objects and contextual parameters.
The @Assisted annotation is for parameters that are specific to the current authentication transaction:
-
Request: The HTTP request that started the authentication journey.
-
Response: The outgoing HTTP response that will be sent to the user agent. You can modify this response, for example, by adding cookies.
-
config: The node configuration object. The type is defined by theconfigClassproperty in the@TreeHook.Metadataannotation. -
Realm: The realm where authentication is taking place.
-
SSOToken: The token that contains session details after a successful authentication.
-
TreeFailureResponse: An object that contains failure details for the
acceptFailure()message and error details for theacceptException()message.
4 The accept() method contains the hook’s core logic. The framework runs this method only after the authentication tree completes successfully.
You can optionally override the acceptFailure() or acceptException() methods to define what happens on failure or exception outcomes.
Register an authentication tree hook
To register a tree hook, your node class must call the addSessionHook() method on an ActionBuilder instance.
For example, the PersistentCookieDecisionNode registers its hook like this:
@Override
public Action process(TreeContext context) throws NodeProcessException {
...
actionBuilder = actionBuilder
.replaceSharedState(context.sharedState.copy().put(USERNAME, userName))
.withUniversalId(identityService.getUniversalId(userName, realm, USER))
.withIdentifiedIdentity(userName, USER)
.putSessionProperty(generateSessionPropertyName(config.persistentCookieName()),
config.persistentCookieName())
.addSessionHook(UpdatePersistentCookieTreeHook.class, nodeId, getClass().getSimpleName());
...
You can specify a node version in the addSessionHook() method.
This lets you associate different tree hooks with different node versions.
If you omit the version, it defaults to version 1 of the node.
Learn more about the addSessionHook() method in ActionBuilder.