Conversation
Janus validates the token on every request, `keepalive` included. Once a signed token expires, keepalives start failing with 403 Unauthorized, Janus stops seeing the session as alive and destroys it after `session_timeout` (60 s by default). Without a way to replace the token, its TTL is a hard ceiling on session lifetime — our voice calls dropped at a fixed interval after connecting. `_tokenMap` is already read per request rather than cached, so exposing the field is enough: assigning a fresh token takes effect on the next request and the session survives, with no reconnect, renegotiation or audio gap. Verified against Janus 1.4.1 (`token_auth` + `token_auth_secret`): the same session that answers 403 with an expired token answers `ack` a second later once a fresh token is sent. Behaviour is unchanged for callers that never touch the setter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
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.
What this changes
Adds a getter and setter for the auth token on
JanusClient:That's the whole change.
_tokenMapis already read per request rather than cached, so assigning a new token takes effect on the next request.Why
Janus validates the token on every request,
keepaliveincluded — not only oncreateandattach. With signed tokens (token_auth_secret), that means an expiring token silently kills a live session:403 Unauthorized request (wrong or missing secret/token)session_timeout(60 s by default) it destroys the sessionBecause the token can only be set in the constructor, its TTL becomes a hard ceiling on session lifetime. With a 5-minute token, every session dies 6 minutes after it was created. That is how we found this: voice dropped at a fixed interval after connecting, on every client, staggered by connect time.
Evidence
Tested against Janus 1.4.1 with
token_auth = trueandtoken_auth_secretset, over a rawjanus-protocolWebSocket.Keepalive is rejected once the token expires (TTL 15 s, keepalive every 3 s):
Control: with a 300 s token, 45 s of keepalives every 3 s → 14 ack, 0 failures. Keepalive itself is fine; the only variable is expiry.
Janus accepts a new token on an already-running session. Same session id, one second apart:
Janus has no notion of "refreshing" a token because it validates statelessly per request — sending a different string is all that is needed, and the session survives with no reconnect, renegotiation or audio gap.
Impact
None for existing callers. The behaviour is identical unless the setter is called.
We are running this in production in a push-to-talk application: both a Flutter iOS app and a Flutter Web admin fetch a fresh short-lived token from their backend every 4 minutes under a 5-minute TTL and assign it. Sessions now survive indefinitely, and voice no longer drops on a timer.
Note
The same argument applies to
_apiSecret, which is stored the same way. We left it alone because it does not normally expire — happy to add it if you'd prefer symmetry.