Webhooks
Verification
Secure your webhook via HMAC signature verification
Middleware
In order to not expose your webhook endpoint to the public, you can verify the signature of the incoming payload and cross-reference it with your signing key you got from the dashboard. For details on HMAC security, review this Wikipedia page.
Make sure not to share your signing key with anyone. If you believe your signing key has been compromised, be sure to refresh it from the Penciled dashboard.
Example webhook endpoint
router.post('/webhook', securityMiddleware, async (req: Request, res: Response) => {
console.log("/webhook req.body: ", req.body);
// save recording, transcript, outcome, etc
})
Example middleware
export const securityMiddleware = async (req: Request, res: Response, next: NextFunction) => {
try {
const signingKey = process.env.PENCILED_SIGNING_KEY; // from the dashboard
const signature = req.headers['x-penciled-signature'] as string;
const verified: boolean = verifyWebhookSignature(signingKey, JSON.stringify(req.body), signature);
if (!verified) {
console.error('Webhook verification failed');
return res.status(401).json({ error: 'Unauthorized' });
}
console.log('Webhook payload verified');
next();
} catch (error) {
console.error('Error verifying webhook:', error);
res.status(401).send('Unauthorized');
}
};
Verify Webhook Signature
import crypto from 'crypto';
/**
* Verifies the signature of a webhook payload using the provided key.
*
* @param secretKey - The key on-hand to verify the signature. Located in environment variables
* @param data - The body of the request
* @param signature - The signature that came in the request headers
* @returns A boolean indicating whether the signature is valid
*/
export function verifyWebhookSignature(secretKey: string, data: any, signature: string): boolean {
const expectedSignature = crypto.createHmac('sha256', secretKey)
.update(data)
.digest('hex');
return expectedSignature === signature;
}