Public Key & Signature Verification
Creating Your Key Pair
Request
const FORMS_API_BASE_URL = 'https://api.visiontree.com/v1'
const TENANT_ID = '1'
const AUTH_TOKEN = 'Your_Auth_Token'
const options = {
headers: {
Authorization: `Bearer ${AUTH_TOKEN}`,
},
}
axios
.post(
`${FORMS_API_BASE_URL}/tenant/${TENANT_ID}/webhook-public-key`,
null,
options
)
.then((res) => console.log(res.data))Response
{
id: 'e15f83b7-1686-464e-b0a9-c09cc7b24835',
tenantId: '1',
publicKey: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQWFoa2k4VVUvUW9vYm9JR1BXZnhRODdQUE1WRDA5Y3czKzFVODJHNElxRkE9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=',
createdOn: '2023-12-07T13:05:08.682Z',
updatedOn: '2023-12-07T13:05:08.682Z'
}Retrieving Your Public Key
Request
const FORMS_API_BASE_URL = 'https://api.visiontree.com/v1'
const TENANT_ID = '1'
const AUTH_TOKEN = 'Your_Auth_Token'
const options = {
headers: {
Authorization: `Bearer ${AUTH_TOKEN}`,
},
}
axios
.get(`${FORMS_API_BASE_URL}/tenant/${TENANT_ID}/webhook-public-key`, options)
.then((res) => console.log(res.data))Response
{
id: 'e15f83b7-1686-464e-b0a9-c09cc7b24835',
tenantId: '1',
publicKey: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQWFoa2k4VVUvUW9vYm9JR1BXZnhRODdQUE1WRDA5Y3czKzFVODJHNElxRkE9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=',
createdOn: '2023-12-07T13:05:08.682Z',
updatedOn: '2023-12-07T13:05:08.682Z'
}Public Key Request & Response
Request
We will discuss the request line-for-line next. First, we made use of the axios library to simplify promise-based HTTP requests. You may use any HTTP library of your choosing. The following three lines set our base Forms API URL, our Tenant ID as well as our Auth Token previously retrieved. The Tenant ID here will be used to retrieve your tenant's public key for securing your webhook with Forms API.
Next, we have a GET request which will return the public key for your Tenant ID.
Response
The request's response contains your Tenant ID's public key, which will be used to verify each webhook's request.
Verify Signature
Forms API uses a EdDSA signature that is added to each request header to your webhook to help you secure your webhook and to trust incoming requests are only from the Forms API. We recommend that you use a signature verification library to manage this verification for you.
Before we show an example of what your verification logic may look like in your webhook it is important to know that we provide 2 headers to every request we send through the webhook:
1) X-PROMs-API-Webhook-Signature
2) X-PROMs-API-Webhook-TimestampThe X-PROMs-API-Webhook-Signature header contains the request's signature which you will validate your incoming requests against and the X-PROMs-API-Webhook-Timestamp provides a timestamp of the request so that you can guard against replay-attacks. Below we will show how to verify a signature of an incoming webhook response:
import { verify } from 'node:crypto'
export const webhookHandler = (request) => {
// get public key from environment, database or Forms API
const publicKey = Buffer.from('LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQWFoa2k4VVUvUW9vYm9JR1BXZnhRODdQUE1WRDA5Y3czKzFVODJHNElxRkE9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=', 'base64').toString('utf8')
// retrieve signature from header
const headerSignature = request.headers['X-PROMs-API-Webhook-Signature']
// verify signature
const isValidRequest = verify(null, Buffer.from(request.body as string), { key: publicKey }, Buffer.from(headerSignature, 'base64'))
if (isValidRequest) {
// ... webhook logic here
}
}