From 9e21ea3d3864ecdbe64d37a03d407e0447f423af Mon Sep 17 00:00:00 2001 From: Max Goldfarb Date: Fri, 9 Oct 2026 13:58:02 -0400 Subject: [PATCH 1/3] docs: use organization Copilot Requests permission for server-to-server tokens --- docs/auth/server-to-server-tokens.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/auth/server-to-server-tokens.md b/docs/auth/server-to-server-tokens.md index b7b4fcf409..98103f4cc4 100644 --- a/docs/auth/server-to-server-tokens.md +++ b/docs/auth/server-to-server-tokens.md @@ -27,15 +27,14 @@ The organization's **Allow use of Copilot CLI billed to the organization** polic For services outside GitHub Actions: -1. Create a GitHub App with the **Copilot Requests** repository permission set to **Read & write**. -1. Install it on the organization that should be billed. The current Copilot permission check requires **All repositories** access. -1. [Create an installation access token](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app) with a repository ID and the Copilot permission: +1. Create a GitHub App with the **Copilot Requests** organization permission set to **Read-only**. +1. Install it on the organization that usage should be attributed and billed to. +1. [Create an installation access token](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app) with the Copilot permission: ```json { - "repository_ids": [123456789], "permissions": { - "copilot_requests": "write" + "organization_copilot_requests": "read" } } ``` @@ -186,16 +185,16 @@ Mint a new installation token before the current token expires. For a child proc ## Billing -Usage is attributed and billed to the account that owns the GitHub App installation. Use an organization installation for organization billing; a user-account installation attributes usage to that user. +Usage is attributed and billed to the organization that owns the GitHub App installation. ## Troubleshooting | Symptom | Check | |---|---| -| `401 Unauthorized` | Confirm the organization supports GitHub App installation authentication for Copilot. | +| `401 Unauthorized` | The token may be expired or invalid. Mint a new installation token. | +| `403` stating that Copilot requests with GitHub App installation access tokens are not enabled | Confirm the organization supports GitHub App installation authentication for Copilot. | | `403 Resource not accessible by integration` or an error mentioning user information | Confirm the installation token is in `COPILOT_GITHUB_TOKEN`, not the SDK's explicit token option. | -| `403 Forbidden` from the Copilot API | Confirm the token request contains `repository_ids` and `copilot_requests: write`. | -| `403 Forbidden` with the required token request | Confirm the app installation has **All repositories** access, then mint a new token. | +| `403 Forbidden` from the Copilot API | Confirm the installation has the organization **Copilot Requests** permission, then mint a new token. | | Requested model is unavailable | Confirm the organization's Copilot policy allows the model and the bundled runtime supports it. | | Wrong account billed | Confirm the installation belongs to the intended organization. | From 301c5f467db6ecacd1889c8633230ffb62dd14b7 Mon Sep 17 00:00:00 2001 From: Max Goldfarb Date: Mon, 12 Oct 2026 15:09:10 -0400 Subject: [PATCH 2/3] docs: pass installation tokens through the SDK token option useLoggedInUser: false makes the runtime ignore environment variable tokens such as COPILOT_GITHUB_TOKEN, so the server-to-server guide example never authenticated. Use the explicit SDK token option instead and note the behavior in the auth docs. --- docs/auth/README.md | 2 +- docs/auth/authenticate.md | 2 +- docs/auth/server-to-server-tokens.md | 35 ++++++++++------------------ 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/docs/auth/README.md b/docs/auth/README.md index a85d6de6e8..2cb074e516 100644 --- a/docs/auth/README.md +++ b/docs/auth/README.md @@ -8,6 +8,6 @@ Choose the authentication method that best fits your deployment scenario for the ## Authentication priority -When multiple credentials are configured, an explicit SDK token takes priority, followed by direct Copilot API environment authentication, environment variable GitHub tokens, stored Copilot CLI credentials, and then GitHub CLI credentials. Server-to-server installation tokens use the environment variable path. See [Authenticate Copilot SDK](authenticate.md#authentication-priority) for details. +When multiple credentials are configured, an explicit SDK token takes priority, followed by direct Copilot API environment authentication, environment variable GitHub tokens, stored Copilot CLI credentials, and then GitHub CLI credentials. GitHub App installation tokens outside GitHub Actions use the explicit SDK token. See [Authenticate Copilot SDK](authenticate.md#authentication-priority) for details. For multi-user server mode, pass a per-session `gitHubToken` so each session runs with the correct GitHub identity; see [Multi-user and server deployments](../setup/multi-tenancy.md). diff --git a/docs/auth/authenticate.md b/docs/auth/authenticate.md index a7582b5510..f45b33c775 100644 --- a/docs/auth/authenticate.md +++ b/docs/auth/authenticate.md @@ -530,7 +530,7 @@ For multi-user server mode, pass a per-session `gitHubToken` so each session run ## Disabling auto-login -To prevent the SDK from automatically using stored credentials or `gh` CLI auth, configure it to disable logged-in-user fallback: +To prevent the SDK from automatically using stored credentials or `gh` CLI auth, configure it to disable logged-in-user fallback. This also ignores environment variable tokens such as `COPILOT_GITHUB_TOKEN`, so you must pass a token through the SDK's explicit token option. The examples below show only the fallback setting:
.NET diff --git a/docs/auth/server-to-server-tokens.md b/docs/auth/server-to-server-tokens.md index 98103f4cc4..c5089cba51 100644 --- a/docs/auth/server-to-server-tokens.md +++ b/docs/auth/server-to-server-tokens.md @@ -39,12 +39,12 @@ For services outside GitHub Actions: } ``` -1. Pass the resulting `ghs_` token to the runtime as `COPILOT_GITHUB_TOKEN`. +1. Pass the resulting `ghs_` token to the SDK's `gitHubToken`, `github_token`, or equivalent option. The organization must be enabled for Copilot requests from GitHub App installations. Installation tokens expire after one hour. -> [!WARNING] -> Do not pass an installation token through the SDK's `gitHubToken`, `github_token`, or equivalent option. That option is for user tokens. Installation tokens must use the runtime environment authentication path. +> [!NOTE] +> No signed-in user is required. `useLoggedInUser: false` turns off automatic credential discovery, including environment variable tokens such as `COPILOT_GITHUB_TOKEN`, so pass the installation token through the SDK's explicit token option. ## Configure the runtime @@ -61,10 +61,7 @@ if (!token) throw new Error("INSTALLATION_TOKEN is required"); const client = new CopilotClient({ connection: RuntimeConnection.forStdio(), - env: { - ...process.env, - COPILOT_GITHUB_TOKEN: token, - }, + gitHubToken: token, useLoggedInUser: false, }); ``` @@ -80,7 +77,7 @@ from copilot import CopilotClient, RuntimeConnection client = CopilotClient( connection=RuntimeConnection.for_stdio(), - env={**os.environ, "COPILOT_GITHUB_TOKEN": os.environ["INSTALLATION_TOKEN"]}, + github_token=os.environ["INSTALLATION_TOKEN"], use_logged_in_user=False, ) ``` @@ -106,7 +103,7 @@ func main() { } client := copilot.NewClient(&copilot.ClientOptions{ Connection: copilot.StdioConnection{}, - Env: append(os.Environ(), "COPILOT_GITHUB_TOKEN="+token), + GitHubToken: token, UseLoggedInUser: copilot.Bool(false), }) _ = client @@ -124,7 +121,7 @@ fn main() { let token = std::env::var("INSTALLATION_TOKEN").expect("INSTALLATION_TOKEN is required"); let options = ClientOptions::new() .with_transport(Transport::Stdio) - .with_env([("COPILOT_GITHUB_TOKEN", token)]) + .with_github_token(token) .with_use_logged_in_user(false); drop(options); } @@ -135,20 +132,15 @@ fn main() { .NET ```csharp -using System.Collections; using GitHub.Copilot; var token = Environment.GetEnvironmentVariable("INSTALLATION_TOKEN") ?? throw new InvalidOperationException("INSTALLATION_TOKEN is required"); -var environment = Environment.GetEnvironmentVariables() - .Cast() - .ToDictionary(entry => (string)entry.Key, entry => entry.Value?.ToString() ?? ""); -environment["COPILOT_GITHUB_TOKEN"] = token; await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForStdio(), - Environment = environment, + GitHubToken = token, UseLoggedInUser = false, }); ``` @@ -160,16 +152,13 @@ await using var client = new CopilotClient(new CopilotClientOptions ```java import com.github.copilot.CopilotClient; import com.github.copilot.rpc.CopilotClientOptions; -import java.util.HashMap; import java.util.Objects; -var environment = new HashMap<>(System.getenv()); var token = Objects.requireNonNull( System.getenv("INSTALLATION_TOKEN"), "INSTALLATION_TOKEN is required"); -environment.put("COPILOT_GITHUB_TOKEN", token); try (var client = new CopilotClient(new CopilotClientOptions() - .setEnvironment(environment) + .setGitHubToken(token) .setUseLoggedInUser(false))) { // Use the client. } @@ -177,11 +166,11 @@ try (var client = new CopilotClient(new CopilotClientOptions()
-For in-process FFI, set `COPILOT_GITHUB_TOKEN` in the host environment before loading the runtime; per-client environment options are not supported. For an existing runtime URI, set it on that runtime process. +For in-process FFI, use the same token option; environment variable tokens in the host process are ignored when `useLoggedInUser` is false. For an existing runtime URI, set `COPILOT_GITHUB_TOKEN` on that runtime process. ## Refresh tokens -Mint a new installation token before the current token expires. For a child process, restart the SDK client with the new environment. For an in-process or existing runtime, restart the host runtime with the new token. +Mint a new installation token before the current token expires. For a child process, restart the SDK client with the new token. For an in-process or existing runtime, restart the host runtime with the new token. ## Billing @@ -193,7 +182,7 @@ Usage is attributed and billed to the organization that owns the GitHub App inst |---|---| | `401 Unauthorized` | The token may be expired or invalid. Mint a new installation token. | | `403` stating that Copilot requests with GitHub App installation access tokens are not enabled | Confirm the organization supports GitHub App installation authentication for Copilot. | -| `403 Resource not accessible by integration` or an error mentioning user information | Confirm the installation token is in `COPILOT_GITHUB_TOKEN`, not the SDK's explicit token option. | +| `No GitHub OAuth token or Copilot HMAC key provided` or `Not authenticated` | Confirm the installation token is passed through the SDK's explicit token option. With `useLoggedInUser: false`, the runtime ignores `COPILOT_GITHUB_TOKEN` and other environment variable tokens. | | `403 Forbidden` from the Copilot API | Confirm the installation has the organization **Copilot Requests** permission, then mint a new token. | | Requested model is unavailable | Confirm the organization's Copilot policy allows the model and the bundled runtime supports it. | | Wrong account billed | Confirm the installation belongs to the intended organization. | From 1ae896a504fbbb334d10e82b8fefbbf0c67cfff9 Mon Sep 17 00:00:00 2001 From: Max Goldfarb Date: Mon, 12 Oct 2026 15:59:16 -0400 Subject: [PATCH 3/3] docs: note existing runtime URI token setup SDK token options are rejected for RuntimeConnection.forUri, so the token must be set as COPILOT_GITHUB_TOKEN on the runtime process. --- docs/auth/README.md | 2 +- docs/auth/server-to-server-tokens.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth/README.md b/docs/auth/README.md index 2cb074e516..d75e9a46f8 100644 --- a/docs/auth/README.md +++ b/docs/auth/README.md @@ -8,6 +8,6 @@ Choose the authentication method that best fits your deployment scenario for the ## Authentication priority -When multiple credentials are configured, an explicit SDK token takes priority, followed by direct Copilot API environment authentication, environment variable GitHub tokens, stored Copilot CLI credentials, and then GitHub CLI credentials. GitHub App installation tokens outside GitHub Actions use the explicit SDK token. See [Authenticate Copilot SDK](authenticate.md#authentication-priority) for details. +When multiple credentials are configured, an explicit SDK token takes priority, followed by direct Copilot API environment authentication, environment variable GitHub tokens, stored Copilot CLI credentials, and then GitHub CLI credentials. GitHub App installation tokens outside GitHub Actions use the explicit SDK token, or `COPILOT_GITHUB_TOKEN` on the runtime process for an existing runtime URI. See [Authenticate Copilot SDK](authenticate.md#authentication-priority) for details. For multi-user server mode, pass a per-session `gitHubToken` so each session runs with the correct GitHub identity; see [Multi-user and server deployments](../setup/multi-tenancy.md). diff --git a/docs/auth/server-to-server-tokens.md b/docs/auth/server-to-server-tokens.md index c5089cba51..0ce6c3f7f7 100644 --- a/docs/auth/server-to-server-tokens.md +++ b/docs/auth/server-to-server-tokens.md @@ -39,7 +39,7 @@ For services outside GitHub Actions: } ``` -1. Pass the resulting `ghs_` token to the SDK's `gitHubToken`, `github_token`, or equivalent option. +1. Pass the resulting `ghs_` token to the SDK's `gitHubToken`, `github_token`, or equivalent option. For an existing runtime URI, set it as `COPILOT_GITHUB_TOKEN` on the runtime process instead. The organization must be enabled for Copilot requests from GitHub App installations. Installation tokens expire after one hour.