Skip to content

Add invalidate() to the token source trait - #1592

Closed
MaxHeimbrock wants to merge 2 commits into
max/room-restart-event-orderfrom
max/token-source-invalidate-dispatch
Closed

MaxHeimbrock wants to merge 2 commits into
max/room-restart-event-orderfrom
max/token-source-invalidate-dispatch

Conversation

@MaxHeimbrock

@MaxHeimbrock MaxHeimbrock commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Add invalidate() to the token source trait. Stacked on #1591.

invalidate() can be used to invalidate a token once it was used for agent dispatch, since joining the same room twice in a row will not trigger a second dispatch. Now the invalidate() can be called on the token source trait itself, not only on the cached version. Also double wrapped .cached() sources are invalidating recursively (see test).

@MaxHeimbrock MaxHeimbrock changed the title livekit-token-source: add invalidate() and dispatches_agent() Add invalidate() and dispatches_agent() Oct 28, 2026
@MaxHeimbrock
MaxHeimbrock force-pushed the max/token-source-invalidate-dispatch branch from ca54629 to 793fade Compare October 29, 2026 09:43
@MaxHeimbrock
MaxHeimbrock force-pushed the max/room-restart-event-order branch from 5c25a50 to 085b9b7 Compare October 29, 2026 09:43
…ent()

Code generic over a configurable token source had no way to drop cached
credentials, because invalidate() existed only on TokenSourceCached.
Add it as a default trait method. TokenSourceCached clears its store and
forwards inward, so a source that is cached twice is cleared at every
layer; the inherent method now does the same.

dispatches_agent() reads roomConfig.agents from the unverified claims, so
a caller can tell whether the token will dispatch an agent without
depending on livekit-token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxHeimbrock
MaxHeimbrock force-pushed the max/token-source-invalidate-dispatch branch from 793fade to 0d617b7 Compare October 29, 2026 09:55
An agent registered without a name is dispatched automatically into every
new room, so a token without roomConfig.agents can still bring an agent
in. The helper's false therefore did not mean "no agent is coming", which
is exactly how its only caller read it. Drop it rather than ship an API
that invites that reading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxHeimbrock MaxHeimbrock changed the title Add invalidate() and dispatches_agent() Add invalidate() to the token source trait Oct 29, 2026
@MaxHeimbrock
MaxHeimbrock added this pull request to stack #1598 October 29, 2026 14:57
Comment on lines +195 to +199
// Through the trait, as code generic over the source would call it.
async fn invalidate(source: &(dyn TokenSourceConfigurable + Send + Sync)) {
source.invalidate().await;
}
invalidate(&cached).await;

@1egoman 1egoman Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Can you swap this for a fully qualified TokenSourceConfigurable::invalidate (or if you went with my other suggestion, TokenSourceCached::invalidate) call?

Suggested change
// Through the trait, as code generic over the source would call it.
async fn invalidate(source: &(dyn TokenSourceConfigurable + Send + Sync)) {
source.invalidate().await;
}
invalidate(&cached).await;
// Through the trait, as code generic over the source would call it.
TokenSourceConfigurable::invalidate(&cached).await;

Comment on lines 73 to 81

/// Drops any cached credentials so the next fetch hits the backend.
///
/// The default does nothing, for sources that cache nothing.
/// [`TokenSourceCached`] clears its store and then forwards to the source
/// it wraps, so a source cached more than once is cleared at every layer.
async fn invalidate(&self) {}

/// Wraps this source in a caching layer that stores the last fetched

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I would think that TokenSourceCached should have the invalidate method, not TokenSourceConfigurable? Avoiding these types of no-op methods was a big reason why we opted to split out fixed / configurable token sources in the first place.

If you split this out then I think the session api layer would need to become a bit more aware of TokenSourceCached, but I don't know if that is necesarily a bad thing, just like how it has to know about TokenSourceConfigurable / TokenSourceFixed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this some more and the idea was nice:
Prevent a cached token source passed into the session from messing with agent dispatch. But we also offer a fixed token source to be used in the session, and that has the same issue with agent dispatch, reusing the same token on reconnecting.

There was no cleaner way I found today unifying the use of fixed and configurable and the generic cached sources in a nicer way than this. And I agree that putting invalidate into token_source.rs feels like leaking the caching concept, which lives as a wrapper in caching.rs as an optional add-on.

So I tried to keep things simpler now, as we do in the other SDKs, and not make this a concern for now. What do you think @1egoman.

@MaxHeimbrock

Copy link
Copy Markdown
Contributor Author

Closing without merging. The Session crate (#1593) no longer invalidates its token source on disconnect, matching the Swift SDK's Session, so nothing needs invalidate() on the TokenSourceConfigurable trait. #1593 is now stacked directly on #1591. The branch tip was 68910ce if this is ever needed again.

@MaxHeimbrock
MaxHeimbrock removed this pull request from stack #1598 November 2, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants