diff --git a/extensions/copilot/src/platform/authentication/node/copilotTokenManager.ts b/extensions/copilot/src/platform/authentication/node/copilotTokenManager.ts index 7f1996f2c72..d1f501620be 100644 --- a/extensions/copilot/src/platform/authentication/node/copilotTokenManager.ts +++ b/extensions/copilot/src/platform/authentication/node/copilotTokenManager.ts @@ -103,10 +103,14 @@ export abstract class BaseCopilotTokenManager extends Disposable implements ICop * @todo this should be not be public, but it is for now to allow testing. */ async authFromGitHubToken( - githubToken: string + githubToken: string, + ghUsername: string ): Promise { this._telemetryService.sendGHTelemetryEvent('auth.new_login'); - const response = await this.fetchCopilotToken(githubToken); + const [response, userInfo] = await Promise.all([ + this.fetchCopilotToken(githubToken), + this.fetchCopilotUserInfo(githubToken) + ]); if (!response) { this._logService.warn('Failed to get copilot token'); this._telemetryService.sendGHTelemetryErrorEvent('auth.request_failed'); @@ -149,12 +153,8 @@ export abstract class BaseCopilotTokenManager extends Disposable implements ICop // adjust expires_at to the refresh time + a buffer to avoid expiring the token before the refresh can fire. tokenInfo.expires_at = nowSeconds() + tokenInfo.refresh_in + 60; // extra buffer to allow refresh to happen successfully - - // extend the token envelope - const userInfo = await this.fetchCopilotUserInfo(githubToken); - const authedUser = await this._baseOctokitservice.getCurrentAuthedUserWithToken(githubToken); - const login = authedUser?.login ?? 'unknown'; + const login = ghUsername ?? 'unknown'; let isVscodeTeamMember = false; // VS Code team members are guaranteed to be a part of an internal org so we can check that first to minimize API calls if (containsInternalOrg(tokenInfo.organization_list ?? [])) { @@ -262,6 +262,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager constructor( private readonly githubToken: string, + private readonly githubUsername: string, @ILogService logService: ILogService, @ITelemetryService telemetryService: ITelemetryService, @IDomainService domainService: IDomainService, @@ -275,7 +276,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager async getCopilotToken(force?: boolean): Promise { if (!this.copilotToken || this.copilotToken.expires_at < nowSeconds() - (60 * 5 /* 5min */) || force) { - const tokenResult = await this.authFromGitHubToken(this.githubToken); + const tokenResult = await this.authFromGitHubToken(this.githubToken, this.githubUsername); if (tokenResult.kind === 'failure') { throw Error( `Failed to get copilot token: ${tokenResult.reason.toString()} ${tokenResult.message ?? ''}` @@ -288,7 +289,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager async checkCopilotToken() { if (!this.copilotToken || this.copilotToken.expires_at < nowSeconds()) { - const tokenResult = await this.authFromGitHubToken(this.githubToken); + const tokenResult = await this.authFromGitHubToken(this.githubToken, this.githubUsername); if (tokenResult.kind === 'failure') { return tokenResult; } diff --git a/extensions/copilot/src/platform/authentication/test/node/copilotToken.spec.ts b/extensions/copilot/src/platform/authentication/test/node/copilotToken.spec.ts index c7cd8cd9ced..5ad455fe7d2 100644 --- a/extensions/copilot/src/platform/authentication/test/node/copilotToken.spec.ts +++ b/extensions/copilot/src/platform/authentication/test/node/copilotToken.spec.ts @@ -73,7 +73,7 @@ describe('Copilot token unit tests', function () { accessor = disposables.add(testingServiceCollection.createTestingAccessor()); const tokenManager = disposables.add(accessor.get(IInstantiationService).createInstance(RefreshFakeCopilotTokenManager, 1)); - await tokenManager.authFromGitHubToken('fake-token'); + await tokenManager.authFromGitHubToken('fake-token', 'fake-user'); expect(fetcher.requests.size).toBe(2); }); @@ -103,7 +103,7 @@ describe('Copilot token unit tests', function () { testingServiceCollection.define(IFetcherService, fetcher); accessor = disposables.add(testingServiceCollection.createTestingAccessor()); - const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid'); + const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid', 'invalid-user'); const result = await tokenManager.checkCopilotToken(); expect(result).toEqual({ kind: 'failure', @@ -121,7 +121,7 @@ describe('Copilot token unit tests', function () { testingServiceCollection.define(IFetcherService, new ErrorFetcherService(expectedError)); accessor = disposables.add(testingServiceCollection.createTestingAccessor()); - const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid'); + const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid', 'invalid-user'); try { await tokenManager.checkCopilotToken(); } catch (err: any) { @@ -172,7 +172,7 @@ describe('Copilot token unit tests', function () { accessor = disposables.add(testingServiceCollection.createTestingAccessor()); const tokenManager = disposables.add(accessor.get(IInstantiationService).createInstance(RefreshFakeCopilotTokenManager, 1)); - await tokenManager.authFromGitHubToken('fake-token'); + await tokenManager.authFromGitHubToken('fake-token', 'invalid-user'); expect(fetcher.requests.size).toBe(2); }); diff --git a/extensions/copilot/src/platform/authentication/vscode-node/copilotTokenManager.ts b/extensions/copilot/src/platform/authentication/vscode-node/copilotTokenManager.ts index 3b74afde8ed..3ab6d738058 100644 --- a/extensions/copilot/src/platform/authentication/vscode-node/copilotTokenManager.ts +++ b/extensions/copilot/src/platform/authentication/vscode-node/copilotTokenManager.ts @@ -66,7 +66,7 @@ export class VSCodeCopilotTokenManager extends BaseCopilotTokenManager { } // Log the steps by default, but only log actual token values when the log level is set to debug. this._logService.info(`Logged in as ${session.account.label}`); - const tokenResult = await this.authFromGitHubToken(session.accessToken); + const tokenResult = await this.authFromGitHubToken(session.accessToken, session.account.label); if (tokenResult.kind === 'success') { this._logService.info(`Got Copilot token for ${session.account.label}`); }