Skip to content

Cache auth tokens client-side to dedupe agent host authenticate RPCs#312017

Merged
roblourens merged 2 commits intomainfrom
roblou/agents/client-authentication-issue-exploration
Apr 22, 2026
Merged

Cache auth tokens client-side to dedupe agent host authenticate RPCs#312017
roblourens merged 2 commits intomainfrom
roblou/agents/client-authentication-issue-exploration

Conversation

@roblourens
Copy link
Copy Markdown
Member

The local and remote agent host contributions were re-firing authenticate RPCs on every rootState change, every default-account change, and every VS Code auth session change — even when the token had not changed. The server-side string compare absorbed this, producing repeated [Copilot] Auth token unchanged log lines for every redundant call.

Fix

Add an AgentHostAuthTokenCache that tracks the last token sent per protected-resource URI. Skip the RPC when the token is unchanged.

  • Local agent host: cache lifetime is per-contribution (one local host).
  • Remote agent host: cache lives on ConnectionState, so it's dropped on disconnect.

The cache is also seeded from the interactive auth path so the first eager pass doesn't re-fire after an interactive sign-in.

Tests

  • 5 unit tests for AgentHostAuthTokenCache (first token / repeat unchanged / rotation / per-URI independence / clear)
  • 3 integration tests against AgentHostContribution exercising the real _authenticateWithServer path:
    • Same token across multiple rootState events → exactly 1 authenticate call
    • Token rotation → 2nd call fires, then dedupe re-engages
    • No resolvable token → 0 calls (no spurious empty-token RPCs)

(Written by Copilot)

Copilot AI review requested due to automatic review settings April 22, 2026 21:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds client-side deduplication of agent-host authenticate RPCs by caching the last token sent per protected resource, reducing redundant auth calls triggered by repeated root-state and auth-session events.

Changes:

  • Introduces AgentHostAuthTokenCache to track last-sent tokens per resource and determine whether an authenticate RPC is necessary.
  • Applies token-dedupe behavior to both local (AgentHostContribution) and remote (RemoteAgentHostContribution) agent-host authentication flows (including interactive auth seeding).
  • Adds unit tests for the cache and integration-style tests validating dedupe behavior through the real contribution auth path.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts Adds integration tests asserting authenticate RPCs are deduped across rootState changes and token rotation.
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostAuth.test.ts Adds unit tests for AgentHostAuthTokenCache.
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostChatContribution.ts Adds token caching + dedupe to local agent-host authentication, and seeds cache from interactive auth.
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostAuth.ts Introduces AgentHostAuthTokenCache.
src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts Adds token caching + dedupe to remote agent-host authentication and interactive auth path.

Copilot's findings

Comments suppressed due to low confidence (2)

src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts:568

  • In the interactive auth flow, the cache is updated before calling authenticate when a token is already resolvable. If that call fails, the cache will treat the token as current and may suppress subsequent retries. Consider seeding the cache only after authenticate succeeds (or reverting the update on error).
					const token = await this._resolveTokenForResource(resourceUri, resource.authorization_servers ?? [], resource.scopes_supported ?? []);
					if (token) {
						authTokenCache?.updateAndIsChanged(resource.resource, token);
						await loggedConnection.authenticate({
							resource: resource.resource,
							token,
						});

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostChatContribution.ts:322

  • In the interactive auth path, the cache is updated before calling authenticate when a token is already resolvable. If the RPC fails, the cache will still treat the token as current and future auth passes may be skipped even though the server never received/accepted it. Updating the cache only after a successful authenticate (or rolling back on failure) would avoid this failure mode.
				const resolved = await resolveTokenForResource(resourceUri, resource.authorization_servers || [], resource.scopes_supported || [], this._authenticationService, this._logService, '[AgentHost]');
				if (resolved) {
					this._authTokenCache.updateAndIsChanged(resource.resource, resolved);
					await this._loggedConnection!.authenticate({
						resource: resource.resource,
						token: resolved,
					});
  • Files reviewed: 5/5 changed files
  • Comments generated: 3

Comment thread src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHost.contribution.ts Outdated
The local and remote agent host contributions were re-firing 'authenticate'
RPCs on every rootState change, every default-account change, and every
VS Code auth session  even when the token had not changed. Thechange
server-side string compare absorbed this, producing repeated
'[Copilot] Auth token unchanged' log lines for every redundant call.

Add an AgentHostAuthTokenCache that tracks the last token sent per
protected-resource URI. Skip the RPC when the token is unchanged. Cache
lifetime is per-contribution for the local agent host and per-connection
for remote agent hosts (so it's dropped on disconnect).

Tests:
- 5 unit tests for AgentHostAuthTokenCache (first/repeat/rotate/per-URI/clear)
- 3 integration tests against AgentHostContribution exercising the real
  _authenticateWithServer path (dedupe holds, rotation re-fires, no-token
  is a no-op)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@roblourens roblourens force-pushed the roblou/agents/client-authentication-issue-exploration branch from 05216b9 to 35d38d7 Compare April 22, 2026 22:02
- Seed the auth token cache only after a successful authenticate RPC
  (not before) so a transient RPC failure doesn't suppress future retries
- On RPC failure, evict the per-resource cache entry so the next auth
  pass will retry that resource
- Clear the entire cache when the local agent host process (re)starts,
  preventing the first post-restart authenticate from being skipped as
  'token unchanged'
- Same fixes applied to the remote agent host contribution

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: 1f9cd94d Current: 69ad3da2

Changed (2)

chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
editor/inlineCompletions/other/JumpToHint/Dark
Before After
before after

@roblourens roblourens marked this pull request as ready for review April 22, 2026 22:24
@roblourens roblourens enabled auto-merge (squash) April 22, 2026 22:24
@roblourens roblourens merged commit 246a575 into main Apr 22, 2026
40 of 41 checks passed
@roblourens roblourens deleted the roblou/agents/client-authentication-issue-exploration branch April 22, 2026 22:33
@vs-code-engineering vs-code-engineering Bot added this to the 1.118.0 milestone Apr 22, 2026
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.

3 participants