The following countries require mobile network operator (MNO) consent to integrate Verified Users. Please contact your Prove representative to discuss requirements.
  • Canada

Prerequisites

  • Sandbox credentials: Ensure you have Prove Sandbox credentials from the Developer Portal. To access Sandbox credentials, follow the steps outlined on the Authentication page. To access the Prove API, use your OAuth client ID and client secret. Load these from environment variables or another method:
// Get environment variables.
clientID := os.Getenv("PROVE_CLIENT_ID")
if len(clientID) == 0 {
  return fmt.Errorf("missing env variable: %s", "PROVE_CLIENT_ID")
}

clientSecret := os.Getenv("PROVE_CLIENT_SECRET")
if len(clientSecret) == 0 {
  return fmt.Errorf("missing env variable: %s", "PROVE_CLIENT_SECRET")
}

proveEnv := "uat-us" // Use UAT in US region.

// Create client for Prove API.
client := provesdkservergo.New(
  provesdkservergo.WithServer(proveEnv),
  provesdkservergo.WithSecurity(components.Security{
    ClientID:     provesdkservergo.String(clientID),
    ClientSecret: provesdkservergo.String(clientSecret),
  }),
)
Token ExpirationThe OAuth token expires after 60 minutes, requiring you to get another token.
  • Server-side SDK: Install the server-side SDK of your choice by running a command in your terminal, or by using a dependency management tool specific to your project.
# The Go library is hosted on GitHub so you can use this command to import it
# to your Go application.
go get github.com/prove-identity/prove-sdk-server-go

# Ensure you import the SDK in your code like this:
import (
	provesdkservergo "github.com/prove-identity/prove-sdk-server-go"
	"github.com/prove-identity/prove-sdk-server-go/models/components"
)
  • Client-side SDK: Install the client-side SDK of your choice by running a command in your terminal, or by using a dependency management tool specific to your project.
To integrate Verified Users with Possession, you must use the client-side SDK.
# Run this command to install the package (ensure you have the latest version).
npm install @prove-identity/prove-auth@2.8.2

Implement Prove Verified Users

1

Prompt Customer

Create or update your first screen to prompt the customer for phone number, first name, and last name.
2

Determine Type of Flow

You can determine if the customer is on a mobile or desktop browser using this example. If the isMobile is true, set mobile as the possessionType for the Start() function on the server, otherwise you can set desktop:
// Check if the customer is on a mobile or desktop browser.
const authCheck = new proveAuth.AuthenticatorBuilder().build();
let isMobile = authCheck.isMobileWeb()
3

Call the Verify Endpoint

On the back end, you’ll start a Prove flow with a call to the Verify() function. This function takes these required parameters:
  • possessionType: either desktop or mobile to describe which type of device the customer is starting their flow on.
  • phoneNumber: the phone number of the customer.
  • firstName: the first name of the customer.
  • lastName: the last name of the customer.
  • finalTargetURL: required when possessionType=desktop. This should be a URL you maintain. Once the customer clicks the Instant Link, they will be redirected to this URL. It should instruct the customer to continue the workflow. Maximum length is 128 characters.
The optional parameters:
  • smsMessage: a field to customize the message body sent in the Instant Link or OTP SMS message. Otherwise, you can use Prove defaults.
  • clientCustomerId: a client-generated unique ID for a specific customer. You can link calls related to the same customer, across different requests or sessions. The client defines the format of this ID.
  • clientRequestId: a client-generated unique ID for a specific request. You can identify specific requests using this field. You determine the format of this ID.
  • allowOTPRetry: set to true to allow the customer to re-enter the OTP up to three times. Defaults to false.
    For OTP retries, make sure to implement client SDK changes in the next step.
// Send the verify request.
rspVerify, err := client.V3.V3VerifyRequest(ctx, &components.V3VerifyRequest{
  FirstName:      "Addy",
  LastName:       "Epinay",
  PhoneNumber:    "2001004010",
  PossessionType: "desktop",
  FinalTargetURL: provesdkservergo.String("https://www.example.com"),
  AllowOTPRetry: true,
})
if err != nil {
  t.Fatal(err)
}
The function returns the following fields:
  • authToken: send this to your client-side code through the Authenticate() function - it’s a JSON Web Token (JWT) tied to the current flow and used for the possession checks. It expires after 15 minutes.
  • correlationId: save this in your current session, then pass it in to VerifyStatus() of the same flow. The correlation ID ties together different system calls for the same Prove flow. It can aids in troubleshooting. The session expires in 15 minutes from when the correlation ID returns from the Verify() call.
  • possessionResult: will return pending since the possession check needs to complete first.
  • verifyResult: pending since the verification check needs to complete first.
  • success: the result of the combination of verifyResult and possessionResult. A result of pendingis returned until the Verify and Possession checks are completed.
Return the authToken in a response to the front end.
4

Authenticate

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);
}

Configure OTP

To use the Resend/Retry/Phone Change features, you need to install the Web SDK version 2.15.1 or later.
To set the One-Time Password (OTP) handler, withOtpFallback(startStep: OtpStartStep | OtpStartStepFn, finishStep: OtpFinishStep | OtpFinishStepFn), requires implementing the OtpStartStep and OtpFinishStep. When returning the phone number in the functions, ensure you return an object with the field phoneNumber to the resolve() function. The default implementation is below, but you can also view the other tabs if you wish to enable advanced capabilities.The OTP session has a two minute timeout from when it’s sent through Short Message Service (SMS) to when the customer can enter in the OTP.
Follow these instructions if you are implementing OTP and you are passing in the phone number on the /v3/start endpoint. In this case, you’ve already prompted for a phone number so you don’t need to prompt for it in the client SDK.Since you passed the phone number in the Start() function, call resolve(null) to communicate to the SDK you have the customer’s agreement to deliver the SMS message. Ensure you return an object to resolve() function.
function otpStartStep(phoneNumberNeeded, phoneValidationError) {
  return new Promise((resolve, reject) => {
    // Since no phone number is needed, don't prompt the user.
    resolve(null);
  });
}
Call the reject('some error message') method to communicate to the SDK any issues while trying to obtain the phone number or the OTP. Report an error if the customer cancels the SMS transaction or presses the back button to leave the screen.In the finish step, call the resolve(result: OtpFinishResult) method to return the collected OTP value in which result variable has OnSuccess value for OtpFinishResultType and the OTP value wrapped in OtpFinishInput.
function otpFinishStep(otpError) {
  return new Promise((resolve, reject) => {
    // If error message is found, handle it.
    if (otpError) {
      // Set to a variable and display it in a field.
      // In this example, we don't do anything with the error.
      var someErrorMessage = otpError.message
    }

    // Prompt the user for whether they received the SMS.
    // Typically, this is a page that shows the OTP already. We are simplifying
    // it by requiring an input.
    var input = confirm('Did you receive a text message?');
    if (!input) {
      // Close the modal if a text message was not received.
      return
    }
      
    // Prompt the user for the OTP.
    var otp = prompt('Enter OTP code:');
    if (otp) {
      // If the input is valid and the user clicked `OK`, return the OTP.
      resolve({
        input: {otp},  // OTP value
        resultType: 0, // OnSuccess enum type = 0
      });
    } else {
      // Else, exit the flow.
      reject('phone invalid or user cancelled');
    }
  });
}
To use the Resend/Retry/Phone Change features, you need to install the Web SDK version 2.15.1 or later.
To set the Instant Link handler, withInstantLinkFallback(startStep: InstantLinkStartStep | InstantLinkStartStepFn, retryStep?: InstantLinkRetryStep | InstantLinkRetryStepFn) requires implementing the InstantLinkStartStep interface and optionally the InstantLinkRetryStep interface if you wish for advanced capabilities. When returning the phone number in the functions, ensure you return an object with the field phoneNumber to the resolve() function.The Instant Link session has a three minute timeout from when it’s sent through Short Message Service (SMS) to when the customer can click the received link.
Follow these instructions if you are implementing Instant Link and you are passing in the phone number on the /v3/start endpoint. In this case, you’ve already prompted for a phone number so you don’t need to prompt for it in the client SDK.Since you passed the phone number in the Start() function, call resolve(null) to communicate to the SDK you have the customer’s agreement to deliver the SMS message. Ensure you return an object to resolve() function.
function instantLinkStartStep(phoneNumberNeeded, phoneValidationError) {
  return new Promise((resolve, reject) => {
    // Since no phone number is needed, don't prompt the user.
    resolve(null);
  });
}
In the desktop flow, a WebSocket opens for three minutes on the desktop browser while waiting for the customer to select the link in the text message. Once clicked, the WebSocket closes and the AuthFinishStep function finishes.
If you’re using Content Security Policy headers, ensure you allow wss: device.uat.prove-auth.proveapis.com and wss: device.prove-auth.proveapis.com.
5

Verify Mobile Number

In the AuthFinishStep, you’ll specify a function to call once the possession checks complete on the mobile phone. This endpoint on your back end server calls the VerifyStatus() function to validate the phone number. The AuthFinishStep then completes.
// Send a verify request to get return customer 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;
}
6

Validate Possession and Ownership of Mobile Phone

Once the possession checks finish on the mobile device, the finish handler on the client-side SDK executes. You then make a request to your server such as POST /verify-status to make the next call in the flow to the VerifyStatus() function.This function requires the Correlation ID which is returned by the Verify() function.
rspVerifyStatus, err := client.V3.V3VerifyStatusRequest(context.TODO(), &components.V3VerifyStatusRequest{
  CorrelationID: rspVerify.V3VerifyStatusRequest.CorrelationID,
})
if err != nil {
  return fmt.Errorf("error on VerifyStatus(): %w", err)
}
The function returns the following fields:
  • success: The result of the combination of Verify Result and Possession Result. Possible values are true or false.
  • possessionResult: either success if the possession check was successful or failed if it failed.
  • verifyResult: either success if the verification was successful or failed if it failed, or not_applicable if possession failed.
You can then respond to the front end with the results of the customer verification.

Webhook notifications

Webhook notifications are only available for US-based phone numbers.
Configure webhooks to receive change events notifications for verified, enrolled customers. Here’s how to get these webhook notifications up and running:
1

Access the Portal

Login to the Portal.
2

Find Your Project

Navigate to your Verified Users project.
3

Configure Webhook

Using the Configure tab, select the Configure button next to the Sandbox webhook. You will be presented with a screen that looks like this:
Enter the URL of your webhook endpoint and select Save and Test Webhook. This will save your configuration and send a test webhook to the URL you provided.
If you would like a sample URL to test, you can use Webhook.site to generate a unique URL for testing.
4

Authenticate Webhook

The webhook URL must be authenticated using Prove’s JWT secret. The JWT is a synchronous JWT using HS256 (synchronous algorithm).This secret is used to sign the JWT token that Prove sends with the webhook notifications. Open the webhook configuration and add the appropriate code snippet to your server-side implementation, replacing whsec_your_secret with the secret provided by the Portal.
The secret value is autogenerated when the appropriate URL is entered and you select Save and Test Webhook or Configure Webhook.
5

Parse the Webhook Payload

The following snippet shows an example of each type of change event you could receive from Prove. Each notification will come as an array of event objects.
Example Payload
{
    "notifications": [
        {
            "eventId": "6ab42d26-8ed2-453f-a4a4-ac305aa50332",
            "event": "phone number change detected",
            "eventType": "PHONE_NUMBER_CHANGE",
            "eventTimestamp": "2025-01-23T10:11:12Z",
            "clientCustomerId": "74ed2189-bde0-4f09-9a7b-0f534259b7b5",
            "identityId": "64ec34e4-6b91-427c-839c-b443dd1570fc"
        },
        {
            "eventId": "0c07d8e3-185c-4b5b-a27b-71ad9ee916b1",
            "event": "phone number disconnected",
            "eventType": "DISCONNECT",
            "eventTimestamp": "2025-01-23T10:11:12Z",
            "clientCustomerId": "f1ea13d2-22ed-433f-94b8-a9026d265797",
            "identityId": "b479a9cb-4dbd-424f-b51e-e4e5bdef8541"
        },
        {
            "eventId": "cbb5f37f-d8e2-4044-955e-a5beec4ddf63",
            "event": "phone number moved out of coverage",
            "eventType": "MOVED_OUT_OF_COVERAGE",
            "eventTimestamp": "2025-01-23T10:11:12Z",
            "clientCustomerId": "62467a14-7ac1-4e36-83f9-77f44ec26f16",
            "identityId": "c3a1a59f-d255-4293-b167-9d007b40db6f"
        }
    ]
}
If you would like to stop receiving notifications for an identity, make a request to the /deactivate endpoint. This will stop all notifications for that identity.
6

Access Production

Once you have successfully tested the webhook and finished your implementation, configure and test your production webhook URL. This will allow you to receive notifications for live events.
Why Am I Not Receiving Notifications?
  • Prove will not send retroactive notifications that occur before the webhook is configured.
  • An identity that has been deactivated will not receive any further notifications.
  • By nature of each change event, an event triggering for an identityId will result in no further notifications for that identity. In the event your customer provides an updated phone number, we’d recommend initiating a new verification with the updated identity information. If verification is successful, Prove will monitor the updated phone number.

Test Your Prove Implementation

Next, reference the Sandbox test scenarios to test users and simulate different behaviors encountered in production.
Production LaunchTo launch in Production, please contact your Prove representative.