/** * Twilio Webhook Signature Validation Middleware * * Validates that incoming requests are genuinely from Twilio by verifying * the X-Twilio-Signature header using HMAC-SHA1 per Twilio's spec. * * @see https://www.twilio.com/docs/usage/security#validating-requests */ import type { Context, Next } from "hono"; /** * Compute the expected Twilio signature for a request. * * Algorithm (per Twilio docs): * 1. Take the full URL of the request * 2. Sort POST body params alphabetically by key * 3. Append each key-value pair to the URL (no separators) * 4. HMAC-SHA1 the result with the auth token, then Base64 encode */ export declare function computeTwilioSignature(authToken: string, url: string, params: Record): string; /** * Validate a Twilio request signature */ export declare function validateTwilioSignature(authToken: string, signature: string, url: string, params: Record): boolean; /** * Options for {@link twilioSignatureMiddleware}. */ export interface TwilioSignatureOptions { /** * Accept requests when no auth token is configured, i.e. run with signature * validation switched off. Development and local testing only — with this on, * anyone who can reach the webhook can impersonate Twilio. Default: false. */ allowUnsigned?: boolean; } /** * Build the URL Twilio used when it computed its signature. * * Twilio signs the full request URL *including* the query string, so a * webhook configured with query parameters (`/sms?tenant=acme`) only * validates when they are preserved here. */ export declare function signedRequestUrl(requestUrl: string, path: string, baseUrl?: string): string; /** * Hono middleware factory for Twilio signature validation. * * Fails closed: without an auth token there is no way to tell a genuine Twilio * request from a forged one, so every request is rejected with 403 unless * `allowUnsigned` is explicitly set. */ export declare function twilioSignatureMiddleware(authToken?: string, baseUrl?: string, options?: TwilioSignatureOptions): (c: Context, next: Next) => Promise)>;