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, you’ll need to use your OAuth client ID and client secret. You can 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 Expiration

The 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 solutions, 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 Unify

To integrate the Prove Unify solution, you must use the client-side SDK.

1

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 flowType 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()
2

Initialize the Flow

You need to send a request to your back end server with the phone number anad possession type to start the flow.

Additional parameters:

  • finalTargetURL: required when flowType=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.

  • smsMessage: optional 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 session. You can identify specific requests using this field. You determine the format of this ID.

// Send the Unify request.
rspUnify, err := client.V3.V3UnifyRequest(ctx, &components.V3UnifyRequest{
  PhoneNumber:    "2001004014",
  PossessionType: "mobile",
  ClientRequestID: provesdkservergo.String("client-abc-123"),
})
if err != nil {
  t.Fatal(err)
}

The function returns the following fields:

  • authToken: send this to your client-side code to pass into the Authenticate() function - it’s a short lived JSON Web Token (JWT) tied to the current flow and used for the possession checks.

  • correlationId: save this in your current session, then pass it in to the UnifyStatus() function call of the same flow. The correlation ID ties together different system calls for the same Prove flow. It also aids in troubleshooting. The session expires in 15 minutes from when the correlation ID returns from the Unify() call.

  • success: will return pending for this initial call.

Return the authToken in a response to the front end.

3

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

There are two functions to implement for the OTP handling - a start and a finish step. The OTP session has a two minute timeout from when it’s sent through SMS to when the customer can enter in the OTP.

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 you passed the phone number in the Start() call, call resolve(null) to communicate to the SDK you have the customer’s agreement to deliver the SMS OTP message. 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 customer 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 has 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 customer 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 has OnResendOtp as value for OtpFinishResultType. The SDK initiates 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 configure for Instant Link. The Instant Link session has a three minute timeout from when it’s sent through SMS to when the customer can selects it.

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 you passed the phone number in the Start() call, call resolve(null) to communicate to the SDK you have the customer’s agreement to deliver the SMS OTP message. 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 customer cancels the Instant Link transaction or presses the back button to leave the Instant Link start step dialog.

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.proveapis.com and wss: device.proveapis.com.
4

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 UnifyStatus() function to validate the phone number. The AuthFinishStep then completes.

rspUnifyStatus, err := client.V3.V3UnifyStatusRequest(context.TODO(), &components.V3UnifyStatusRequest{
CorrelationID: rspUnify.V3UnifyResponse.CorrelationID,
})
if err != nil {
return fmt.Errorf("error on UnifyStatus(): %w", err)
}

The function returns the following fields:

  • success: either true if the mobile number validation was successful, or false if it failed.

  • phoneNumber: the phone number associated with the possession check.

You can then respond to the front end with the results of the authentication.

Test Your Prove Implementation

Next, reference the Sandbox test scenarios to test users and simulate different behaviors encountered in production.

Production Launch

To launch in Production, please contact your Prove representative.