WebAuthN deviceName collector

Use case overview

When authenticating in AM using the WebAuthN out-of-the-box nodes, a new trusted device will be saved in the User’s profile. By default, the device name will be ‘New Security Key’. The same name will be used for every newly registered device. The user can change the device name after the authentication in the user profile > trusted devices section.
Here you can find a way to collect the device name from the user in order to avoid the same name being used.

Prerequisites

  • In the WebAuthnRegistration node, you must enable “Store device data in the transient state”
  • In the Scripted Decision node config, you need to add webauthnDeviceData as script input.

Scripted decision node

The small script in this case just returns a prompt to the user to provide a name for the device he/she is registering for the first time. The user can provide a name or skip and use the default name.

/**
 * Takes the nodeState webauthnDeviceData object, prompts the user for a user-friendly name of the device, 
 * updates the transientState. If user skips it, then it does nothing.
 */

/**
 * Node imports
 */
var javaImports = JavaImporter(
    org.forgerock.openam.auth.node.api.Action,
    javax.security.auth.callback.ConfirmationCallback,
    javax.security.auth.callback.NameCallback,
    java.lang.String
);

/**
 * Node outcomes
 */

var nodeOutcomes = {
    SAVE: "save",
    SKIP: "skip"
};

/**
 * Node config
 */

var nodeConfig = {
    BUTTONS: ["SAVE", "SKIP"],
    SAVE_ACTION_PRESSED: 0,
    SKIP_ACTION_PRESSED: 1,
    deviceDataSharedStatePropertyName: "webauthnDeviceData",
    callbackDisplayTextDeviceNameInput: "Security key name",
    nodeName: "***SecurityKeyNameCollector"
};


/**
 * Node logger
 */

var nodeLogger = {
    debug: function(message) {
        logger.message("***" + nodeConfig.nodeName + " " + message);
    },
    warning: function(message) {
        logger.warning("***" + nodeConfig.nodeName + " " + message);
    },
    error: function(message) {
        logger.error("***" + nodeConfig.nodeName + " " + message);
    }
};

/**
 * Main
 */

(function() {
    nodeLogger.debug("node executing");
    if (callbacks.isEmpty()) {
        action = javaImports.Action.send(
            javaImports.NameCallback(nodeConfig.callbackDisplayTextDeviceNameInput),
            javaImports.ConfirmationCallback(javaImports.ConfirmationCallback.INFORMATION, nodeConfig.BUTTONS, 0)
        ).build();
    } else {
        var userSelection = callbacks[1].getSelectedIndex();
        nodeLogger.debug("User selected: " + userSelection);
        if (userSelection === nodeConfig.SAVE_ACTION_PRESSED) {
            var deviceInputName = javaImports.String(callbacks.get(0).getName());
            nodeLogger.debug("Setting new device name:" + deviceInputName);
            var webauthnDeviceData = nodeState.get(nodeConfig.deviceDataSharedStatePropertyName);
            webauthnDeviceData.put("deviceName", deviceInputName);
            transientState.put("webauthnDeviceData", webauthnDeviceData);
            action = javaImports.Action.goTo(nodeOutcomes.SAVE).build();
        } else {
            action = javaImports.Action.goTo(nodeOutcomes.SKIP).build();
        }
    }
})();

Journey overview

The WebAuthN registration tree will look like:

Node prompt

Conclusion

So, whilst the default name is not ideal, this is an easy way to overwrite the device name during authentication if the user chooses it.

4 Likes