Orchestration SDKs

Adding strong authentication in JavaScript

PingOne JavaScript

The FIDO module offers a streamlined API for handling FIDO interactions.

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

Step 1. Installing modules

To add FIDO to your JavaScript apps you need this module:

  • fido

The fido module for JavaScript is exported as a member of the @forgerock/davinci-client npm package.

To install the DaVinci client and member modules:

  • Install the DaVinci client into your JavaScript apps using npm:

    Install the DaVinci client
    npm install @forgerock/davinci-client --save

Step 2. Initialize the FIDO client

You need to import the FIDO module into your project, and initialize both the DaVinci client, and the FIDO API:

  1. In your JavaScript app, import the DaVinci client, and fido module as named imports:

    Import the DaVinci client
    import { davinci, fido } from '@forgerock/davinci-client';
  2. Initialize the DaVinci client, and fido module:

    const davinciClient = await davinci({ config });
    const fidoApi = fido();
    Learn more about initializing the DaVinci client in Configuring the DaVinci module.

Step 3. Registering FIDO authenticators

To register a FIDO authenticator, use the register() function. The function returns a promise with FidoRegistrationInputValue, which contains the correctly-formatted public key credential, or a GenericError:

Registering a FIDO authenticator in a DaVinci flow
if (collector.type === 'FidoRegistrationCollector') {
  const credentialOptions = collector.output.config.publicKeyCredentialCreationOptions;
  const publicKeyCredential = await fidoApi.register(credentialOptions);

  if ('error' in publicKeyCredential) {
    // Handle the error
  }

  // Update the FidoRegistrationCollector with the credential or error
  const updater = davinciClient.update(collector);
  updater(publicKeyCredential);
}

let nextStep = davinciClient.next();

Step 4. Authenticating using a FIDO authenticator

To authenticate using a registered FIDO authenticator, use the authenticate() function. The function returns a promise containing either FidoAuthenticationInputValue, which contains the assertion you can return to DaVinci, or GenericError:

Authenticating with a FIDO authenticator in a DaVinci flow
if (collector.type === 'FidoAuthenticationCollector') {
  const credentialOptions = collector.output.config.publicKeyCredentialRequestOptions;
  const assertion = await fidoApi.authenticate(credentialOptions);

  if ('error' in assertion) {
    // Handle the error
  }

  // Update the FidoAuthenticationCollector with the credential or error
  const updater = davinciClient.update(collector);
  updater(assertion);
}

let nextStep = davinciClient.next();

Step 5. Handling FIDO client-side errors

If a call to register() or authenticate() fails, the returned promise resolves to a GenericError instead of a credential or assertion. That error object carries a code property, typed as FidoErrorCode, which normalizes the underlying WebAuthn DOMException into one of the following values:

  • NotAllowedError

  • AbortError

  • InvalidStateError

  • NotSupportedError

  • SecurityError

  • TimeoutError

  • UnknownError - Returned when the underlying error doesn’t match any of the recognized WebAuthn error names.

The FIDO module does not automatically submit a client-side error back to DaVinci. Reporting the error, and deciding when to progress the flow afterwards, is left to your app.

To report a client-side error, call davinciClient.update(collector) with the error object, the same way you would with a successful credential or assertion, and then call next() when you’re ready to continue the flow:

Reporting a FIDO client-side error to DaVinci
const publicKeyCredential = await fidoApi.register(credentialOptions);

if ('error' in publicKeyCredential) {
  console.error(publicKeyCredential.code, publicKeyCredential.message);

  const updater = davinciClient.update(collector);
  updater(publicKeyCredential); // Send the error’s `code` and `message` back to the flow
}

// Call `next()` when you’re ready to continue, for example after showing the user a message
let nextStep = davinciClient.next();

DaVinci flows can use the reported code to branch. For example, to offer a retry after a TimeoutError, or to fall back to another authentication method after a NotAllowedError.