-
Notifications
You must be signed in to change notification settings - Fork 325
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #509 from aricday/verify-prefill
feat(templates): add verify-prefill template
- Loading branch information
Showing
14 changed files
with
364 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# description: SID of your Twilio Verify Service | ||
# format: sid | ||
# link: https://www.twilio.com/console/verify/services | ||
# required: true | ||
VERIFY_SERVICE_SID= | ||
|
||
# description: Your Lookup API Key. Can be created in the Console. | ||
# required: true | ||
# format: sid | ||
LOOKUP_API_KEY= | ||
|
||
# description: Your Lookup API Secret. Can be created in the Console. | ||
# required: true | ||
# format: secret | ||
LOOKUP_API_SECRET= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
dkundel | ||
alisontanu | ||
pthirumurthi | ||
aricday |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Changelog | ||
|
||
## [Unreleased] | ||
|
||
## [1.0.0] | ||
### Added | ||
- Initial release. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# Twilio Verify: Identity-Prefill-API Demo | ||
|
||
Demo application showing Twilio Verify and Lookup Identity-Prefill APIs | ||
|
||
In today's digital age, user experience is paramount. Every additional step or friction point can deter potential customers, reduce conversion rates, and degrade the overall experience. To combat this, Twilio introduces an innovative feature within its Lookup API: **Identity Pre-Fill** in Private Beta. This powerful tool can revolutionize how businesses handle customer interactions, from onboarding to checkout, by pre-populating user data with verified information. Below, we discuss how this feature works, its potential benefits, and ways you can leverage it through a sample demo app. | ||
|
||
This project demonstrates a phone number verification and prefilling user information using Twilio's Verify and Lookups APIs. Users can enter their phone number, receive an OTP, and verify their phone number. Upon successful verification, additional user details such as name and address will be fetched and displayed after a 90 seconds delay. | ||
|
||
## Features | ||
|
||
- Send OTP to entered phone number using Twilio Verify API. | ||
- Verify OTP entered by the user. | ||
- Fetch and display user information using Twilio Lookups API after successful OTP verification with a 90 seconds delay. | ||
|
||
### What is Identity Pre-Fill? | ||
|
||
**Identity Pre-Fill** is a new pilot preview capability in the Twilio Lookup API that provides the first name, last name, and address of end-users after verifying their phone number possession using Twilio Verify. This data helps pre-populate forms, making the user experience smoother and faster by reducing manual input efforts. | ||
|
||
![verify-prefill](./image.png) | ||
|
||
## Pre-requisites | ||
|
||
### Technical Considerations | ||
|
||
A few technical aspects to keep in mind: | ||
|
||
- Queries to the Identity Pre-Fill API are only accepted within 10 minutes of successful verification through Twilio Verify. | ||
|
||
- This product is only available in the United States during the pilot phase. | ||
|
||
- Use of this product requires the use of the Twilio Verify product. Customers using custom code implementations for verification are not eligible for the pilot. | ||
|
||
### Environment variables | ||
|
||
This project requires some environment variables to be set. A file named `.env` is used to store the values for those environment variables. To keep your tokens and secrets secure, make sure to not commit the `.env` file in git. When setting up the project with `twilio serverless:init ...` the Twilio CLI will create a `.gitignore` file that excludes `.env` from the version history. | ||
|
||
In your `.env` file, set the following values: | ||
|
||
| Variable | Description | Required | | ||
| :------------------- | :---------- | :------- | | ||
| `VERIFY_SERVICE_SID` | Verify SID | True | | ||
| `LOOKUP_API_KEY` | ApiKey | True | | ||
| `LOOKUP_API_SECRET` | ApiSecret | True | | ||
|
||
### Function Parameters | ||
|
||
`/send-otp` expects the following parameters: | ||
|
||
| Parameter | Description | Required | | ||
| :---------- | :----------------- | :------- | | ||
| phoneNumber | E.160 Phone Number | True | | ||
|
||
`/verify-otp` expects the following parameters: | ||
|
||
| Parameter | Description | Required | | ||
| :-------- | :---------- | :------- | | ||
| Code | Verify Code | True | | ||
|
||
`/fetch-user-data` expects the following parameters: | ||
|
||
| Parameter | Description | Required | | ||
| :--------------- | :------------------ | :------- | | ||
| verificationSid | Approved Verify SID | True | | ||
|
||
## Create a new project with the template | ||
|
||
1. Install the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart#install-twilio-cli) | ||
2. Install the [serverless toolkit](https://www.twilio.com/docs/labs/serverless-toolkit/getting-started) | ||
|
||
```shell | ||
twilio plugins:install @twilio-labs/plugin-serverless | ||
``` | ||
|
||
3. Initiate a new project | ||
|
||
``` | ||
twilio serverless:init example --template=verify-prefill && cd example | ||
``` | ||
|
||
4. Start the server with the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart): | ||
|
||
``` | ||
twilio serverless:start | ||
``` | ||
|
||
5. Open the web page at <https://localhost:3000/index.html> and enter your phone number to test | ||
|
||
ℹ️ Check the developer console and terminal for any errors, make sure you've set your environment variables. | ||
|
||
## Deploying | ||
|
||
Deploy your functions and assets with either of the following commands. Note: you must run these commands from inside your project folder. [More details in the docs.](https://www.twilio.com/docs/labs/serverless-toolkit) | ||
|
||
With the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart): | ||
|
||
``` | ||
twilio serverless:deploy | ||
``` | ||
|
||
## Test the Application | ||
|
||
1. Access your Twilio Function URL that serves the `index.html` file. | ||
2. Enter a phone number and click on "Send OTP." | ||
3. Enter the received OTP and click on "Verify OTP." | ||
4. Upon successful verification, wait for 90 seconds, and then user data should be displayed on the webpage. | ||
|
||
### Conclusion | ||
|
||
Identity Pre-Fill is a game-changer for businesses looking to enhance user experiences and streamline processes. By reducing the effort required to fill out forms and ensuring data accuracy while speeding up interactions, you can significantly improve customer satisfaction and conversion rates. | ||
|
||
#### Learn More | ||
|
||
For detailed documentation and more information on Twilio Lookup APIs, visit the [Twilio Lookup API documentation](https://www.twilio.com/docs/lookup/api). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Verify Prefill Demo</title> | ||
</head> | ||
<body> | ||
<h1>Phone Number Verification</h1> | ||
<form id="verification-form"> | ||
<label for="phone-number">Phone Number - E.164:</label> | ||
<input type="tel" id="phone-number" name="phone-number" required> | ||
<button type="button" onclick="sendOTP()">Send OTP</button> | ||
<br><br> | ||
<label for="otp-code">OTP Code:</label> | ||
<input type="text" id="otp-code" name="otp-code" required> | ||
<button type="button" onclick="verifyOTP()">Verify OTP</button> | ||
</form> | ||
<br> | ||
<h2>Identity Lookup Results Below</h2> | ||
<br> | ||
<div id="user-data" style="display:none;"> | ||
<h2>User Data: Results</h2> | ||
<p>First Name: <span id="first-name"></span></p> | ||
<p>Last Name: <span id="last-name"></span></p> | ||
<p>Address Line: <span id="address-line"></span></p> | ||
<p>Country Code: <span id="country-code"></span></p> | ||
<p>State: <span id="state"></span></p> | ||
<p>Postal Code: <span id="postal-code"></span></p> | ||
</div> | ||
|
||
<script> | ||
async function sendOTP() { | ||
const phoneNumber = document.getElementById('phone-number').value; | ||
const response = await fetch('/send-otp', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ phoneNumber }) | ||
}); | ||
const result = await response.json(); | ||
alert(result.message); | ||
} | ||
|
||
async function verifyOTP() { | ||
const phoneNumber = document.getElementById('phone-number').value; | ||
const code = document.getElementById('otp-code').value; | ||
const response = await fetch('/verify-otp', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ phoneNumber, code }) | ||
}); | ||
const result = await response.json(); | ||
if (result.success) { | ||
alert('Verification successful. Fetching user data in 90 seconds...'); | ||
setTimeout(() => fetchUserData(phoneNumber, result.verificationSid), 90000); // 90 seconds delay | ||
} else { | ||
alert('Verification failed: ' + result.message); | ||
} | ||
} | ||
|
||
async function fetchUserData(phoneNumber, verificationSid) { | ||
const response = await fetch('/fetch-user-data', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ phoneNumber, verificationSid }) | ||
}); | ||
const result = await response.json(); | ||
if (result.success) { | ||
displayUserData(result.prefillData); | ||
} else { | ||
alert('Fetching user data failed: ' + result.message); | ||
} | ||
} | ||
|
||
function displayUserData(data) { | ||
document.getElementById('first-name').innerText = data.first_name; | ||
document.getElementById('last-name').innerText = data.last_name; | ||
document.getElementById('address-line').innerText = data.address_line; | ||
document.getElementById('country-code').innerText = data.country_code; | ||
document.getElementById('state').innerText = data.state; | ||
document.getElementById('postal-code').innerText = data.postal_code; | ||
document.getElementById('user-data').style.display = 'block'; | ||
} | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
exports.handler = function (context, event, callback) { | ||
callback(null, {}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
exports.handler = async function (context, event, callback) { | ||
const { phoneNumber } = event; | ||
const { verificationSid } = event; | ||
const lookupApiKey = context.LOOKUP_API_KEY; | ||
const lookupApiSecret = context.LOOKUP_API_SECRET; | ||
|
||
try { | ||
// Use dynamic import to load the node-fetch module | ||
const fetch = (await import('node-fetch')).default; | ||
|
||
const lookupUrl = `https://lookups.twilio.com/v2/PhoneNumbers/${phoneNumber}?Fields=pre_fill&VerificationSid=${verificationSid}`; | ||
const lookupResponse = await fetch(lookupUrl, { | ||
headers: { | ||
Authorization: `Basic ${Buffer.from( | ||
`${lookupApiKey}:${lookupApiSecret}` | ||
).toString('base64')}`, | ||
}, | ||
}); | ||
|
||
const lookupData = await lookupResponse.json(); | ||
|
||
return callback(null, { success: true, prefillData: lookupData.pre_fill }); | ||
} catch (error) { | ||
console.error('Error fetching user data:', error); | ||
return callback(null, { success: false, message: error.message }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
exports.handler = async function (context, event, callback) { | ||
const { phoneNumber } = event; | ||
const { VERIFY_SERVICE_SID: serviceSid } = context; | ||
|
||
// Ensure the Twilio client is initialized | ||
const client = context.getTwilioClient(); | ||
|
||
if (!serviceSid) { | ||
console.error('Missing VERIFY_SERVICE_SID'); | ||
return callback('Missing VERIFY_SERVICE_SID'); | ||
} | ||
|
||
try { | ||
// Validate phone number using Twilio Lookup API with Node.js library | ||
const lookupResponse = await client.lookups.v2 | ||
.phoneNumbers(phoneNumber) | ||
.fetch(); | ||
|
||
if (!lookupResponse.valid) { | ||
const message = | ||
'Invalid phone number. Please enter a valid number in E.164 format.'; | ||
console.error(message, lookupResponse); | ||
return callback(null, { success: false, message }); | ||
} | ||
|
||
// Start verification if the phone number is valid | ||
const verification = await client.verify.v2 | ||
.services(serviceSid) | ||
.verifications.create({ to: phoneNumber, channel: 'sms' }); | ||
|
||
console.log('Verification response:', verification); | ||
|
||
return callback(null, { | ||
success: true, | ||
message: `Verification sent to ${phoneNumber}`, | ||
}); | ||
} catch (error) { | ||
console.error('Error sending OTP:', error); | ||
return callback(null, { success: false, message: error.message }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
exports.handler = async function (context, event, callback) { | ||
const { phoneNumber, code } = event; | ||
const { VERIFY_SERVICE_SID: serviceSid } = context; | ||
|
||
const client = context.getTwilioClient(); | ||
|
||
if (!serviceSid) { | ||
console.error('Missing VERIFY_SERVICE_SID'); | ||
return callback('Missing VERIFY_SERVICE_SID'); | ||
} | ||
|
||
try { | ||
// Verify the OTP using Twilio Verify API V2 | ||
const verificationCheck = await client.verify.v2 | ||
.services(serviceSid) | ||
.verificationChecks.create({ to: phoneNumber, code }); | ||
|
||
console.log('Verification check response:', verificationCheck); | ||
|
||
if (verificationCheck.status === 'approved') { | ||
return callback(null, { | ||
success: true, | ||
verificationSid: verificationCheck.sid, | ||
}); | ||
} | ||
|
||
return callback(null, { | ||
success: false, | ||
message: `Verification failed. Status: ${verificationCheck.status}`, | ||
}); | ||
} catch (error) { | ||
console.error('Error verifying OTP:', error); | ||
return callback(null, { success: false, message: error.message }); | ||
} | ||
}; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "verify-prefill", | ||
"version": "1.0.0", | ||
"private": true, | ||
"dependencies": { | ||
"twilio": "^5.0.4", | ||
"node-fetch": "^3.3.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const { handler } = require('../functions/blank'); | ||
|
||
describe('verify-prefill function template', () => { | ||
it('Calls callback with empty JSON', () => { | ||
const callback = jest.fn(); | ||
handler({}, {}, callback); | ||
expect(callback).toHaveBeenCalledWith(null, {}); | ||
}); | ||
}); |