Supported languages
Prove provides client web SDKs in the following languages: TypeScript and JavaScript.
Installation
The Prove Platform Web SDK has an unpacked size of 324 KB, and a single dependency: @prove-identity/mobile-auth. 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.
# Run this command to install the package (ensure you have the latest version).
npm install @prove-identity/prove-auth@3.1.1
Find the type of flow: mobile or desktop
You can find if the customer 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 customer is on a mobile or desktop browser.
const authCheck = new proveAuth.AuthenticatorBuilder().build();
let isMobile = authCheck.isMobileWeb()
In a mobile flow, the mobile phone validates the one-time password (OTP). In a desktop flow, Instant Link sends a text message to the mobile phone for verification.
In the mobile flow, once the OTP validation completes, the AuthFinishStep function finishes.
In the desktop flow, a WebSocket opens for 3 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.
Authenticate()
The SDK requires an authToken as a parameter for the Authenticate() function. This token returns from the Start() call of the server-side SDK. The token is session specific, limiting it to a single flow. It also expires after 15 minutes.
Retrieve authToken
Send a request to your back end server with the possession type, and an optional phone number if you are using the Prove possession check.
async function initialize(phoneNumber, possessionType) {
const response = await fetch(backendUrl + "/initialize", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
phoneNumber: phoneNumber,
possessionType: possessionType,
}),
});
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.
Mobile Auth Implementations OnlyIf your application uses Content Security Policy headers, you must configure them to allow WebSocket connections to Prove’s authentication services:Sandbox Environment
https://device.uat.proveapis.com:4443
https://device.uat.proveapis.com
http://device.uat.proveapis.com:4443
http://device.uat.proveapis.com
Production Environment
https://device.proveapis.com:4443
https://device.proveapis.com
http://device.proveapis.com:4443
http://device.proveapis.com
https://auth.svcs.verizon.com:22790
Failure to configure these settings prevents Mobile Auth functionality from working correctly in web flows.
const isMobileWeb = flowType.value === "mobile";
const isDesktop = flowType.value === "desktop";
if (isMobileWeb) {
// Set up the authenticator for either mobile or desktop flow.
let builder = new proveAuth.AuthenticatorBuilder();
// Set up Mobile Auth and OTP.
builder = builder
.withAuthFinishStep(() => clientFinished())
.withMobileAuthImplementation("fetch")
.withOtpFallback(otpStart, otpFinish);
} else if (isDesktop){
// Set up Instant Link.
builder = builder
.withAuthFinishStep(() => clientFinished())
.withInstantLinkFallback(instantLink)
.withRole("secondary");
} else {
// Customer provided possession.
builder = builder
.withAuthFinishStep(() => clientFinished());
authenticator.authenticate(authToken);
}
Validate the mobile phone
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 Unify-Status() function to validate the phone number. The AuthFinishStep then completes. If the user cancels, the server makes a call to the Unify-Status() function and returns success=false.
// Send a verify request.
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);
return null;
}
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 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.
Default
Prompt for Phone Number
Resend
Retry OTP
Phone Number Change
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');
}
});
}
Follow these instructions if implementing MobileAuth and collecting the phone number only if MobileAuth fails. This will implement OTP without allowing for SMS resends and phone number changes. If you do want those capabilities, please reference the subsequent tabs (Resend, Retry OTP, and Phone Number Change).In the start step, call the resolve(input: OtpStartInput) method to return the collected phone number to the SDK.function otpStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
The finish step is implemented the same as the previous tab: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');
}
});
}
Follow these instructions to allow the customer to request a new OTP via SMS using the same phone number. There is a max of three send attempts including the initial message.The start step is implemented the same as the previous tab:function otpStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
You can then send a new OTP SMS to the same phone number by implementing the finish step like this: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) {
// If `Cancel`, then resend to the same phone number.
resolve({
resultType: 1, // OnResendOtp enum type = 1
});
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');
}
});
}
Follow these instructions to allow the customer to re-enter the OTP PIN if they type it wrong. There is a max of 3 attempts. To implement this functionality, you also need to pass in allowOTPRetry=true to the /v3/start endpoint.The start step is implemented the same as either of the the previous tabs - no client side code changes necessary:function otpStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
The finish step is implemented the same as either of the the previous tabs - no client side code changes necessary. If the OTP is invalid, the finish step will be called again to prompt the user for a new input. Once the max attempts is reached, the AuthFinish function will be called.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');
}
});
}
Follow these instructions to allow the customer to re-enter their phone number. There is a max of three entries/send attempts.Manual Request RequiredTo enable phone number change capabilities on your credentials, contact your Prove representative.
The start step is implemented the same as the previous tab:function otpStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
You can prompt for a new phone number by implementing the finish step like this: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) {
// If `Cancel`, then trigger the otpStartStep to re-prompt for
// phone number.
resolve({
resultType: 2, // OnMobileNumberChange enum type = 2
});
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.
Default
Prompt for Phone Number
Resend
Phone Number Change
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);
});
}
Follow these instructions if implementing MobileAuth and collecting the phone number for desktop. This will implement Instant Link without allowing for SMS resends and phone number changes. If you do want those capabilities, please reference the subsequent tabs (Resend and Phone Number Change).Call the resolve(input: InstantStartInput) method to return the collected phone number to the SDK.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.function instantLinkStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
Follow these instructions to allow the customer to request a new SMS using the same phone number. There is a max of three send attempts including the initial message.The start step is implemented the same as the previous tab:function instantLinkStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
You can then send a new Instant Link SMS to the same phone number by implementing the InstantLinkRetryStep interface, for example:function instantLinkRetryStep() {
return new Promise((resolve, reject) => {
// There are multiple return options:
// - resolve(0): request resend to the same phone number
// - reject('user clicked cancel'): error out of the possession flow
// Prompt the user for the phone number.
// Typically, this is a page that is automatically closed or redirected
// once the `AuthFinish` function is called. We are simplifying it by
// requiring an input.
var input = confirm('Did you receive a text message?');
if (input) {
// If `OK`, close the modal.
return;
}
// Else `Cancel`, then resend to the same phone number.
resolve(0);
});
}
Follow these instructions to allow the customer to re-enter their phone number. There is a max of three entries/send attempts.Manual Request RequiredTo enable phone number change capabilities on your credentials, contact your Prove representative.
The start step is implemented the same as the previous tab:function instantLinkStartStep(phoneNumberNeeded, phoneValidationError) {
return new Promise((resolve, reject) => {
// If no phone number is needed, then don't prompt the user.
if (!phoneNumberNeeded) {
resolve(null);
return;
}
// If error message is found around phone number, handle it.
// The `phoneValidationError` is ONLY available when `phoneNumberNeeded`
// has a value.
if (phoneValidationError) {
// Set to a variable and display it in a field.
// In this example, we don't do anything with the error.
var someErrorMessage = phoneValidationError.message;
}
// Prompt the user for the phone number.
var input = prompt('Enter phone number:');
if (input) {
// If the input is valid and the user clicked `OK`, return the phone
// number.
resolve({
phoneNumber: input,
});
} else {
// Else, exit the flow.
reject('phone invalid or user cancelled');
}
});
}
You can prompt for a new phone number by implementing the InstantLinkRetryStep interface, for example:function instantLinkRetryStep() {
return new Promise((resolve, reject) => {
// There are multiple return options:
// - resolve(0): request resend to the same phone number
// - resolve(1): request phone number change/re-prompt
// - reject('user clicked cancel'): error out of the possession flow
// Prompt the user for the phone number.
// Typically, this is a page that is automatically closed or redirected
// once the `AuthFinish` function is called. We are simplifying it by
// requiring an input.
var input = confirm('Did you receive a text message?');
if (input) {
// If `OK`, close the modal.
return;
}
// Else `Cancel`, then trigger the instantLinkStartStep to re-prompt for
// phone number.
resolve(1);
});
}