typescript-webhook-example
Version:
Example of a webhook that can be integrated with Transcend.
53 lines (48 loc) • 1.56 kB
text/typescript
// Libraries
import got from 'got';
import jwt from 'jsonwebtoken';
// Constants
import { TRANSCEND_API_KEY, SOMBRA_API_KEY, SOMBRA_URL } from '../constants';
import { logger } from '../logger';
// Global to cache the webhook signing public key
let cachedPublicKey: jwt.Secret | jwt.GetPublicKeyOrSecret;
/**
* Helper to verify incoming webhook requests
*
* Transcend developers: A design choice was made not to put webhook verification on an Express middleware.
* It's a nice refactor, but it can be esoteric to readers.
*
* @param signedToken - the JSON Web Token asymmetrically signed with ES384.
* @returns - the signed body
*/
export async function verifyWebhook(
signedToken: string | string[] | undefined,
): Promise<void> {
// Get the public key and cache it for next time.
if (!cachedPublicKey) {
try {
const response = await got.get(
`${SOMBRA_URL}/public-keys/sombra-general-signing-key`,
{
headers: {
authorization: `Bearer ${TRANSCEND_API_KEY}`,
'x-sombra-authorization': SOMBRA_API_KEY
? `Bearer ${SOMBRA_API_KEY}`
: undefined,
},
},
);
cachedPublicKey = response.body;
} catch (err) {
logger.error('Failed to get public key:', err);
}
}
// Verify webhook signature with the public key (ensures that Transcend sent the request)
return jwt.verify(
Array.isArray(signedToken) ? signedToken.join() : signedToken || '',
cachedPublicKey,
{
algorithms: ['ES384'],
},
);
}