Orchestration SDKs

Integrating FIDO auth journeys in JavaScript

PingOne Advanced Identity Cloud PingAM JavaScript

The FIDO module offers a streamlined API for handling FIDO interactions, including registering and authenticating with passkeys.

It abstracts away the complexities of the underlying FIDO protocols, allowing you to quickly add strong authentication to your applications.

For an example of the journeys you can build with this module, see the sample passkey journey.

Step 1. Installing modules

To add FIDO and WebAuthn capabilities to your JavaScript apps for Journeys you need to import the WebAuthn module. The WebAuthn module for JavaScript is exported as a member of the @forgerock/journey-client npm package.

Install the journey client into your JavaScript apps using npm:

Install the journey client
npm install @forgerock/journey-client --save

Step 2. Importing the WebAuthn module

In your JavaScript app, import the WebAuthn module and step type as named imports:

Import the module and step type
import { WebAuthn, WebAuthnStepType } from '@forgerock/journey-client/webauthn';

Step 3. Registering FIDO authenticators

To register a FIDO authenticator, use the register() function. Pass the step object as a parameter to the method.

The WebAuthn module leverages the WebAuthn APIs built into the browser to create a new credential. It then updates the callbacks in the step with the relevant credentials.

Return the updated step to the server by calling journeyClient.next(), and passing the step as the parameter.

Registering a FIDO authenticator in an auth journey
const webAuthnStep = WebAuthn.getWebAuthnStepType(step);

if (webAuthnStep === WebAuthnStepType.Registration) {
    await WebAuthn.register(step);
}

// Return updated step to server to continue journey
step = await journeyClient.next(step);

The browser displays the appropriate user interface to register a new WebAuthn credential, for example a local-only Passkey:

Creating a local Passkey when Authentication Attachment is set to PLATFORM
Figure 1. Creating a local Passkey when Authentication Attachment is set to PLATFORM

Step 4. Authenticating using a FIDO authenticator

To authenticate using a registered FIDO authenticator, use the authenticate() function. Pass the step object as a parameter to the method.

The WebAuthn module leverages the WebAuthn APIs built into the browser to present the available credentials, and authenticate the user. It then updates the callbacks in the step with the details from the WebAuthn authenticator.

Return the updated step to the server by calling journeyClient.next(), and passing the step as the parameter.

Authenticating with a FIDO authenticator in an auth journey
const webAuthnStep = WebAuthn.getWebAuthnStepType(step);

if (webAuthnStep === WebAuthnStepType.Authentication) {
    await WebAuthn.authenticate(step);
}

// Return updated step to server to continue journey
step = await journeyClient.next(step);

Step 5. Enabling passkey autofill (WebAuthn conditional UI)

Passkey autofill, also known as WebAuthn conditional UI, lets users sign in with a saved passkey directly from the browser’s autofill suggestions when they tap or click the username field, skipping the extra step of pressing a dedicated "Sign in with a passkey" button.

Conditional UI is server-driven: after you configure the journey to enable it, the metadata the server sends with the WebAuthn Authentication step tells the SDK to use conditional mediation automatically. You don’t need to change how you call WebAuthn.authenticate().

To add passkey autofill support to your app:

  1. Add an input field for the username with autocomplete="webauthn".

    The browser requires this attribute on a visible, focusable input before it will show passkey suggestions in the autofill dropdown.

    Adding an autofill-eligible username field
    <input type="text" name="username" autocomplete="webauthn" />
  2. Optionally, feature-detect conditional UI support before relying on it, and provide an AbortSignal so you can cancel the request if the user submits the form a different way:

    Feature-detecting and cancelling conditional mediation
    const supportsConditionalUI = await WebAuthn.isConditionalMediationSupported();
    
    if (supportsConditionalUI) {
      const controller = new AbortController();
    
      // Focus the autofill-eligible field, then start the request in the background
      const webAuthnStep = WebAuthn.getWebAuthnStepType(step);
    
      if (webAuthnStep === WebAuthnStepType.Authentication) {
        WebAuthn.authenticate(step, controller.signal)
          .thenupdatedStep) ⇒ journeyClient.next(updatedStep
          .catch((error) ⇒ {
            // AbortError is expected if you cancel the request yourself
            if (error.name !== 'AbortError') {
              // Handle other failures, for example fall back to a password field
            }
          });
      }
    
      // Later, if the user submits a different sign-in method:
      // controller.abort();
    }

If the server requests conditional mediation but the browser doesn’t support it, authenticate() throws a NotSupportedError. Handle this the same way you handle any other authentication failure, for example by falling back to a password field.