← Back to PRs

#12471: fix(voice-call): pass stream auth token via TwiML Parameter for Twilio Media Streams

by Yida-Dev open 2026-02-09 08:43 View on GitHub →
channel: voice-call stale
## Summary Fixes #12340 Twilio Media Streams **strips query parameters from WebSocket URLs** when connecting to the stream endpoint. This means the auth token embedded in `<Stream url="wss://...?token=abc">` never reaches the server, causing every media stream connection to be rejected with `"invalid token"`. ### Root cause 1. `getStreamUrlForCall()` appends `?token=<random>` to the WebSocket URL 2. `getStreamConnectXml()` places this URL in `<Stream url="...">` 3. **Twilio initiates the WebSocket connection but drops the query string** 4. `getStreamToken()` reads `?token=` from the upgrade request URL -> `undefined` 5. `isValidStreamToken(callSid, undefined)` -> `false` -> stream rejected ### Fix - **TwiML**: Add `<Parameter name="token" value="...">` inside `<Stream>` -- Twilio forwards `<Parameter>` values in the WebSocket `start` message's `customParameters` object - **Token resolution**: Fall back to `start.customParameters.token` in `handleStart()` when the URL query token is missing - **Type**: Add `customParameters?: Record<string, string>` to `TwilioMediaMessage.start` The URL query token is kept as the primary path for backward compatibility; `customParameters` acts as a fallback. ## Test plan - [x] New test: `getStreamConnectXml` includes `<Parameter name="token">` tag - [x] New test: `getStreamConnectXml` omits `<Parameter>` when URL has no token - [x] New test: streaming TwiML for inbound calls includes `<Parameter>` - [x] All existing voice-call tests pass (8/8) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR updates the Twilio Media Streams integration to avoid relying on WebSocket URL query parameters for authentication. `TwilioProvider.getStreamConnectXml()` now adds a `<Parameter name="token" ... />` inside the `<Stream>` verb (so Twilio forwards it in the Media Streams `start.customParameters` payload), and `MediaStreamHandler.handleStart()` falls back to `start.customParameters.token` when the upgrade URL token is missing. Tests were added to confirm the token parameter is included/omitted. <h3>Confidence Score: 4/5</h3> - This PR is largely safe to merge, but the TwiML generation should be adjusted to avoid emitting whitespace text inside `<Stream>` when no `<Parameter>` is present. - Core approach (passing token via `<Parameter>` and reading it from `start.customParameters`) is sound and minimally invasive. The main remaining concern is the exact TwiML shape produced by `getStreamConnectXml()` and the tests not strongly validating XML structure, which could cause Twilio to reject the response in some environments. - extensions/voice-call/src/providers/twilio.ts, extensions/voice-call/src/providers/twilio.test.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs