Supported Languages

Prove provides client web SDKs in the following languages: JavaScript/TypeScript.

Installation

The Prove® Platform Web SDK has an unpacked size of 171 kB, and a single dependency: @prove-identity/mobile-auth. Install the client SDK of your choice by running a command in your terminal, or by using a dependency management tool specific to your project.

# Run this command to install the package (ensure you have the latest version).
npm install @prove-identity/prove-auth@2.8.2

Determine the Type of Flow: Mobile or Desktop

You can determine if the user is on a mobile or desktop browser using this example. If the isMobile is true, pass mobile to the Start() function on the server, otherwise you can pass desktop:

// Check if the end user is on a mobile or desktop browser.
const authCheck = new proveAuth.AuthenticatorBuilder().build();
let isMobile = authCheck.isMobileWeb()

In a mobile flow, Mobile Auth executes first and if that fails, it will perform one-time password (OTP) validation on the mobile phone. In a desktop flow, Instant Link sends a text message to the mobile phone for verification.

In the mobile flow, once either Mobile Auth or the OTP validation is complete, the AuthFinishStep function finishes.

Mobile Auth

In order for Mobile Auth to succeed:

  • Disable VPN.
  • Disable Private Relay on iOS.

When testing, you can ignore any Chrome error messages that mention ERR_TUNNEL_CONNECTION_FAILED - this is due to the VPN, but the SDK will still properly fallback to OTP.

In the desktop flow, a WebSocket opens for two minutes on the desktop browser while waiting for the user to click on the link in the text message. Once clicked, the WebSocket closes and the AuthFinishStep function finishes.

Instant Link

If you are using Content-Security-Policy headers, please ensure you allow wss: device.uat.prove-auth.proveapis.com and wss: device.prove-auth.proveapis.com or you may receive the error message in your browser console: Refused to connect to ... because it violates the following Content Security Policy directive.

Authenticate()

The SDK requires an authToken as a parameter for the Authenticate() function. This token returns from the Start() call of the server SDK. The token is session specific, limiting it to a single flow. It also expires after 15 minutes.

Retrieve authToken

To start the flow, you’ll need to send a request to your backend server with the phone number, flow type, and an optional challenge of either the date of birth (YYYY-MM-DD) or social security number (last four digits).

async function initialize(phoneNumber, ssn, flowType) {
  const response = await fetch(backendUrl + "/initialize", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      phoneNumber: phoneNumber,
      flowType: flowType,
      ssn: ssn,
    }),
  });

  const rsp = await response.json();
  const authToken = rsp.authToken;

  return authToken;
}

Setup Authenticator

Once you have the authToken, build the authenticator for both the mobile and desktop flows.

async function authenticate(isMobileWeb, authToken) {
  // Set up the authenticator for either mobile or desktop flow.
  let builder = new proveAuth.AuthenticatorBuilder();

  if (isMobileWeb) {
    // Set up Mobile Auth and OTP.
    builder = builder
      .withAuthFinishStep((input) => verify(input.authId))
      .withMobileAuthImplementation("fetch")
      .withOtpFallback(otpStart, otpFinish);
  } else {
    // Set up Instant Link.
    builder = builder
      .withAuthFinishStep((input) => verify(input.authId))
      .withInstantLinkFallback(instantLink)
      .withRole("secondary");
  }

  const authenticator = builder.build();

  // Authenticate with the authToken.
  return authenticator.authenticate(authToken);
}

Validate the Mobile Phone

In the AuthFinishStep, you’ll specify a function to call once the possession checks are complete on the mobile phone. This endpoint on your backend server will then call the Validate() function to validate the phone number. If it was successful, the server returns the results from the Challenge() function that will include user information. Included below are a few example fields that return and then are pre-filled on a form for the user to verify. The AuthFinishStep then completes. In the event of cancellation, the server makes a call to the Validate() function and returns success=false.

// Send a verify request to get return user information.
async function verify() {
  const response = await fetch(backendUrl + "/verify", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({}),
  });

  const results = await response.json();
  const rsp = JSON.stringify(results);

  const firstName = document.getElementById("firstNameInput");
  const lastName = document.getElementById("lastNameInput");

  firstName.value = rsp.firstName;
  lastName.value = rsp.lastName;

  return null;
}

OTP Configuration

There are two functions to implement for the OTP handling - a start and a finish step.

In order to set the OTP handler, implement withOtpFallback(startStep: OtpStartStep | OtpStartStepFn, finishStep: OtpFinishStep | OtpFinishStepFn), OtpStartStep and OtpFinishStep. The JavaScript snippet has a simplified example while the TypeScript snippet explains various situations. Ensure you return an object with the field phoneNumber to the resolve() function.

Retry functionality is unavailable using OTP.

function otpStart(phoneNumberNeeded, phoneValidationError) {
  return new Promise((resolve, reject) => {
    if (phoneNumberNeeded) {
      var val = prompt("Enter phone number:");
      let input = {
        phoneNumber: val,
      };
      resolve(input);
    } else {
      resolve(null);
    }
  });
}

Call the resolve(input: OtpStartInput) method to return the collected phone number to the SDK.

If the phone number was already specified in the Start() call, then call resolve(null) to communicate to the SDK that the mobile app has the user’s agreement to deliver the SMS OTP message to the provided phone number. Ensure you return an object to resolve() function.

Call the reject("some error message") method to communicate to the SDK any issues while trying to obtain the phone number. Report an error if the user explicitly cancels the SMS OTP transaction or presses the back button to leave the SMS OTP start step screen.

function otpFinish(err) {
  return new Promise((resolve, reject) => {
    if (err) {
      console.log(err);
    } else {
      var val = prompt(`Enter your OTP:`);

      let result = {
        input: {
          otp: val,
        },
        resultType: 0,
      };

      resolve(result);
    }
  });
}

Call the resolve(result: OtpFinishResult) method to return the collected OTP value in which result variable contains OnSuccess value for OtpFinishResultType and the OTP value wrapped in OtpFinishInput.

Call the reject("some error message") method to communicate to the SDK any issues while trying to obtain the OTP value. Report an error if the user explicitly cancels the SMS OTP transaction or presses the back button to exit out of the SMS OTP finish step screen.

Also call the resolve(result: OtpFinishResult) method to request a SMS OTP message in which the result variable contains OnResendOtp as value for OtpFinishResultType. The SDK will then initiate a OtpStartStep.execute() call to allow the mobile app to restart the phone number collection logic. You can send up to three OTPs during the same authentication session.

There is one function to configuration for Instant Link.

In order to set the Instant Link handler, withInstantLinkFallback(startStep: InstantLinkStartStep | InstantLinkStartStepFn) requires implementing the InstantLinkStartStep interface. The JavaScript snippet has a simplified example while the TypeScript snippet explains various situations. Ensure you return an object with the field phoneNumber to the resolve() function.

function instantLink(phoneNumberNeeded, phoneValidationError) {
  return new Promise((resolve, reject) => {
    if (phoneNumberNeeded) {
      var val = prompt("Enter phone number:");
      let input = {
        phoneNumber: val,
      };
      resolve(input);
    } else {
      resolve(null);
    }
  });
}

Call the resolve(input: InstantStartInput) method to return the collected phone number to the SDK.

If the phone number was already delivered to the Prove server in the Start() call, then resolve(null) calls to communicate to the SDK that the mobile app has the user’s agreement to deliver the Instant Link message to the provided phone number.

Call the reject("some error message") method to communicate to the SDK any issues while trying to obtain the phone number. Report an error if the user explicitly cancels the Instant Link transaction or presses the back button to leave the Instant Link start step dialog.

Verify the User Information

Once the user has made any edits to their pre-fill information, submit that information to the backend server so the Complete() call can then verify the user information.

// Send request to the backend to verify user information.
async function sendInfo(firstName, lastName) {
  const response = await fetch(backendUrl + "/finish", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      firstName: firstName,
      lastName: lastName,
    }),
  });
  const results = await response.json();
  const rsp = JSON.stringify(results);

  return rsp;
}

Function Reference

Initiate the flow with Authenticator.authenticate(), while creating an instance of Authenticator using AuthenticatorBuilder.build().

Use the following methods to configure Authenticator before instantiating. All methods return the same instance of AuthenticatorBuilder to allow chaining of the configuration methods.

withAuthFinishStep(step: AuthFinishStep | AuthFinishStepFn): AuthenticatorBuilder

This step customizes the handling of the authentication finish call. The implementation calls the customer’s backend to retrieve authentication results. The customer defines the format of the response to suit the application needs.

withRole(role: DeviceRole): AuthenticatorBuilder

Sets the authentication role for this device. It can be either Primary or Secondary. The Primary value sets when the end user is on a mobile device web browser that registers directly with Prove system and later authenticated by verifying this registration. On other hand, the Secondary value sets when the end user is on a desktop web browser, which authenticates after receiving user feedback on their Primary device.

withMobileAuthImplementation(implementation: MobileAuthImplementation): AuthenticatorBuilder

Sets the implementation type for Mobile Auth authenticator. Possible values are Fetch or Pixel with Fetch set by default.

withDeviceIpAddress(deviceIp: string | (() => string | null) | null): AuthenticatorBuilder

Sets the public IP address for this device to report during device registration. If you neglect to call this method, or the IP address value is null, the system will attempt to auto-detect the IP address using an external service. If the service is inaccessible, the system will use the client’s IP address of the HTTP connection. Successful Mobile Auth authentication requires the client’s public IP address.

withOtpFallback(startStep: OtpStartStep | OtpStartStepFn, finishStep: OtpFinishStep | OtpFinishStepFn): AuthenticatorBuilder

Configure start and finish handlers for SMS OTP authenticator. Collecting user input requires using these handlers to enter the phone number for delivery of OTP codes, and to enter received OTP codes.

withInstantLinkFallback(startStep: OtpStartStep | OtpStartStepFn): AuthenticatorBuilder

Configure handler for Instant Link authenticator. This handler collects user input to enter the phone number for Instant Link.

build(): Authenticator

Finalizes the configuration and returns an instance of the Authenticator.