1079
1080
private async _buildCopilotToken(githubToken: string): Promise<ICachedCopilotToken> {
1082
>
1083
>
this._logService.debug('[CopilotApiService] Minting Copilot session token');
1084
>
1085
>
const response = await capiClient.makeRequest<Response>(
1086
>
{
1087
>
method: 'GET',
1088
>
headers: {
1089
>
'Authorization': `token ${githubToken}`,
1090
>
'X-GitHub-Api-Version': USER_API_VERSION,
1091
>
},
1092
>
},
1093
>
{ type: RequestType.CopilotToken },
1094
>
);
1095
>
1096
>
if (!response.ok) {
1097
const text = await response.text().catch(() => '');
1098
throw new Error(`Copilot session token mint failed: ${response.status} ${response.statusText} \u2014 ${text}`);
1099
}
1101
>
const envelope = await response.json() as ICopilotTokenEnvelope;
1102
>
if (typeof envelope.token !== 'string' || typeof envelope.expires_at !== 'number') {
1103
throw new Error('Copilot session token mint returned malformed envelope');
1104
}
1106
>
// Prefer `now + refresh_in` over the server-reported `expires_at`:
1107
>
// users with a fast local clock can see `expires_at` already in the
1108
>
// past, which would cause us to re-mint on every call. Mirror what
1109
>
// the Copilot Chat extension's `RefreshableCopilotTokenManager`
1110
>
// does. Floor at `now + 60s` so a malformed/short `refresh_in`
1111
>
// can't trigger a tight re-mint loop.
1112
>
const nowSeconds = Date.now() / 1000;
1113
>
const refreshIn = typeof envelope.refresh_in === 'number' ? envelope.refresh_in : undefined;
1114
>
const organizationList = Array.isArray(envelope.organization_list)
1115
>
? envelope.organization_list.filter((organization): organization is string => typeof organization === 'string')
1116
: [];
1118
>
refreshIn !== undefined ? nowSeconds + refreshIn : envelope.expires_at,
1119
>
nowSeconds + 60,
1120
>
);
1121
>
1122
>
return {
1123
>
token: envelope.token,
1124
>
expiresAt,
1125
>
modelIdsByFamily: new Map(),
1126
>
isInternal: organizationList.some(organization => INTERNAL_COPILOT_ORGANIZATIONS.has(organization)),
1127
>
isVscodeTeamMember: organizationList.some(organization => VSCODE_COPILOT_ORGANIZATIONS.has(organization)),
1128
>
};
1129
>
}
1130
1131
/**