Skip to content

Commit 476ce15

Browse files
committed
feat: add GitHub Enterprise Server support
Add support for GitHub Enterprise Server instances in addition to GitHub.com: - Add dynamic URL construction based on provider config and auth data - Read enterpriseUrl from auth data (priority 1) or provider options (priority 2) - Support both github-copilot and github-copilot-enterprise provider IDs - Normalize enterprise URLs (remove protocol/trailing slashes) The plugin integrates with core's handleGithubCopilotAuth() which prompts users for deployment type and enterprise URL, storing it in auth data. Priority order for enterpriseUrl: 1. Auth data (set by core during interactive authentication) 2. Provider config options 3. Default to github.com This enables enterprise users to authenticate with their GitHub Enterprise Server Copilot instances while maintaining excellent UX.
1 parent 406a939 commit 476ce15

1 file changed

Lines changed: 50 additions & 7 deletions

File tree

index.mjs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,57 @@
33
*/
44
export async function CopilotAuthPlugin({ client }) {
55
const CLIENT_ID = "Iv1.b507a08c87ecfe98";
6-
const DEVICE_CODE_URL = "https://github.com/login/device/code";
7-
const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
8-
const COPILOT_API_KEY_URL =
9-
"https://api.github.com/copilot_internal/v2/token";
106
const HEADERS = {
117
"User-Agent": "GitHubCopilotChat/0.35.0",
128
"Editor-Version": "vscode/1.99.3",
139
"Editor-Plugin-Version": "copilot-chat/0.35.0",
1410
"Copilot-Integration-Id": "vscode-chat",
1511
};
1612

13+
/**
14+
* Normalizes a domain by removing protocol and trailing slashes
15+
*/
16+
function normalizeDomain(url) {
17+
return url
18+
.replace(/^https?:\/\//, "")
19+
.replace(/\/$/, "");
20+
}
21+
22+
/**
23+
* Gets the base URL from auth data, provider config, or defaults to github.com
24+
* Priority: auth data > config > github.com
25+
*/
26+
async function getBaseUrl(providerId, authInfo) {
27+
try {
28+
// First check auth data (set by core during authentication)
29+
if (authInfo && authInfo.enterpriseUrl) {
30+
return normalizeDomain(authInfo.enterpriseUrl);
31+
}
32+
33+
// Then check config
34+
const config = await client.config.get();
35+
const providerConfig = config?.provider?.[providerId];
36+
const configUrl = providerConfig?.options?.enterpriseUrl;
37+
38+
return configUrl ? normalizeDomain(configUrl) : "github.com";
39+
} catch {
40+
return "github.com";
41+
}
42+
}
43+
44+
/**
45+
* Constructs URLs based on the base URL (github.com or enterprise)
46+
*/
47+
async function getUrls(providerId, authInfo) {
48+
const baseUrl = await getBaseUrl(providerId, authInfo);
49+
50+
return {
51+
DEVICE_CODE_URL: `https://${baseUrl}/login/device/code`,
52+
ACCESS_TOKEN_URL: `https://${baseUrl}/login/oauth/access_token`,
53+
COPILOT_API_KEY_URL: `https://api.${baseUrl}/copilot_internal/v2/token`,
54+
};
55+
}
56+
1757
return {
1858
auth: {
1959
provider: "github-copilot",
@@ -36,7 +76,8 @@ export async function CopilotAuthPlugin({ client }) {
3676
const info = await getAuth();
3777
if (info.type !== "oauth") return {};
3878
if (!info.access || info.expires < Date.now()) {
39-
const response = await fetch(COPILOT_API_KEY_URL, {
79+
const urls = await getUrls(provider.id, info);
80+
const response = await fetch(urls.COPILOT_API_KEY_URL, {
4081
headers: {
4182
Accept: "application/json",
4283
Authorization: `Bearer ${info.refresh}`,
@@ -102,7 +143,9 @@ export async function CopilotAuthPlugin({ client }) {
102143
label: "Login with GitHub",
103144
type: "oauth",
104145
authorize: async () => {
105-
const deviceResponse = await fetch(DEVICE_CODE_URL, {
146+
// During authorize, read from config only (no auth data exists yet)
147+
const urls = await getUrls("github-copilot", null);
148+
const deviceResponse = await fetch(urls.DEVICE_CODE_URL, {
106149
method: "POST",
107150
headers: {
108151
Accept: "application/json",
@@ -121,7 +164,7 @@ export async function CopilotAuthPlugin({ client }) {
121164
method: "auto",
122165
callback: async () => {
123166
while (true) {
124-
const response = await fetch(ACCESS_TOKEN_URL, {
167+
const response = await fetch(urls.ACCESS_TOKEN_URL, {
125168
method: "POST",
126169
headers: {
127170
Accept: "application/json",

0 commit comments

Comments
 (0)