fix(licensing): validate each token-2 once per endpoint - #20
Merged
Merged
Conversation
token-2 is a one-time proof, minted at call setup, that an outbound call egressed through a licensed SBC. The feature-server sets it on every provisional response and again after the final response, and later responses carry the same token with its original timestamp. mediajam rejects a token older than 40s, so on any outbound call that rang that long, a re-sent 180/183 failed validation as 'expired' and the endpoint was destroyed (license-violation) before answer. Answered calls then ran with no media until the media timeout. Remember the token-2 that validated and skip re-validating the same token. A different token-2 is still validated; a failed one is not remembered; minting a new token-1 clears it. Seen on a production mini: 42 calls on 2026-09-30, all failing 40-59s after the INVITE; 6 of them answered with the caller never heard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
token-2is a one-time proof, minted at call setup, that an outbound call left through a licensed SBC.Endpoint.set('jambonz_session_token_2', …)validates it vialicensing.validate-token-2every time it's set, and the feature-server (lib/utils/place-outdial.js) sets it on every provisional response and again after the final response. Later responses carry the same token with its original timestamp, and mediajam rejects tokens older than 40 s (internal/license/token.go,tokenTTLSeconds).So on any outbound call that rings for more than 40 seconds, a re-sent 180/183 fails as
session token invalid: expired, and this module destroys the endpoint (license-violation) before the call is answered. If the callee then answers, the call runs with no media until the media timeout.Seen on a production jambonz mini (mediajam 0.5.8, feature-server 11.1.5) on 2026-09-30: 42 calls, every failure 40.3–59.1 s after the INVITE (median 50.0 s). 36 were never answered. 6 were answered after the failure: the agent ran, but the caller was never heard, and the call ended after about 38 s of silence.
Fix
_validateSessionToken2remembers the token-2 that validated and skips re-validating the same token. The first check happens on the first provisional, while the token is seconds old, so the anti-replay window is unchanged.Raising the 40 s TTL instead was considered and rejected: it only moves the cliff (carriers ring 60–120 s) and widens the replay window.
Tests
Four new tests in
test/licensing-conduit.test.js, using a validator that accepts a token once and then rejects it as expired, like mediajam after 40 s. The long-ring test fails without the fix.npm test: 105 pass, 0 fail (8 skipped). Lint clean.Follow-up
After release, bump
@jambonz/mrfin feature-server (main and the 11.1.5 customer branch).🤖 Generated with Claude Code