diff --git a/docs/README.md b/docs/README.md index 9e0d8fddf..74736509e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ Welcome to the GitHub Copilot SDK docs. Whether you're building your first Copil |---|---| | **Build my first app** | [Getting Started](./getting-started.md)—end-to-end tutorial with streaming & custom tools | | **Set up for production** | [Setup Guides](./setup/README.md)—architecture, deployment patterns, scaling | -| **Configure authentication** | [Authentication](./auth/README.md)—GitHub OAuth, environment variables, BYOK | +| **Configure authentication** | [Authentication](./auth/README.md)—GitHub OAuth, server-to-server authentication, environment variables, BYOK | | **Add features to my app** | [Features](./features/README.md)—hooks, custom agents, MCP, skills, and more | | **Debug an issue** | [Troubleshooting](./troubleshooting/debugging.md)—common problems and solutions | @@ -35,6 +35,7 @@ How to configure and deploy the SDK for your use case. Configuring how users and services authenticate with Copilot. * [Authentication Overview](./auth/README.md): methods, priority order, and examples +* [Server-to-server authentication](./auth/server-to-server-tokens.md): use GitHub Actions or GitHub App installation tokens for organization-attributed automation * [Bring Your Own Key (BYOK)](./auth/byok.md): use your own API keys from OpenAI, Azure, Anthropic, and more ### [Features](./features/README.md) diff --git a/docs/auth/README.md b/docs/auth/README.md index 282bcb019..a85d6de6e 100644 --- a/docs/auth/README.md +++ b/docs/auth/README.md @@ -3,10 +3,11 @@ Choose the authentication method that best fits your deployment scenario for the GitHub Copilot SDK. * [Authenticate Copilot SDK](authenticate.md): methods, priority order, and examples +* [Server-to-server authentication](server-to-server-tokens.md): use GitHub Actions or GitHub App installation tokens for organization-attributed automation * [Bring your own key (BYOK)](./byok.md): use your own API keys from OpenAI, Azure, Anthropic, and more ## 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. 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. Server-to-server installation tokens use the environment variable path. 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 1a0190186..97492c1fc 100644 --- a/docs/auth/authenticate.md +++ b/docs/auth/authenticate.md @@ -9,6 +9,7 @@ The GitHub Copilot SDK supports multiple authentication methods to fit different | [GitHub Signed-in User](#github-signed-in-user) | Interactive apps where users sign in with GitHub | Yes | | [OAuth GitHub App](#oauth-github-app) | Apps acting on behalf of users via OAuth | Yes | | [Environment Variables](#environment-variables) | CI/CD, automation, server-to-server | Yes | +| [Server-to-server authentication](./server-to-server-tokens.md) | Organization-attributed automation and direct organization billing | No user subscription; organization policy required | | [BYOK (Bring Your Own Key)](./byok.md) | Using your own API keys (Azure AI Foundry, OpenAI, and more) | No | ## GitHub signed-in user @@ -236,6 +237,8 @@ client.start().get(); For automation, CI/CD pipelines, and server-to-server scenarios, you can authenticate using environment variables. +For organization-attributed automation that should not use a user's personal access token, see [Server-to-server authentication](./server-to-server-tokens.md). + **Supported environment variables (in priority order):** 1. `COPILOT_GITHUB_TOKEN` - Recommended for explicit Copilot usage 1. `GH_TOKEN` - GitHub CLI compatible diff --git a/docs/auth/server-to-server-tokens.md b/docs/auth/server-to-server-tokens.md new file mode 100644 index 000000000..b7b4fcf40 --- /dev/null +++ b/docs/auth/server-to-server-tokens.md @@ -0,0 +1,205 @@ +# Server-to-server authentication + +Use a short-lived installation access token when a service needs to make Copilot requests on behalf of an organization without a user's credentials. In GitHub Actions, use the built-in `GITHUB_TOKEN` instead. + +## GitHub Actions + +For workflows in an organization-owned repository, grant the built-in token permission to make Copilot requests: + +```yaml +permissions: + contents: read + copilot-requests: write + +jobs: + copilot: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - run: your-application + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` + +The organization's **Allow use of Copilot CLI billed to the organization** policy must be enabled. This approach needs no GitHub App or stored authentication secret. For details, see [Using Copilot CLI in GitHub Actions with GITHUB_TOKEN](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli-in-actions). + +## Other services and CI systems + +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: + + ```json + { + "repository_ids": [123456789], + "permissions": { + "copilot_requests": "write" + } + } + ``` + +1. Pass the resulting `ghs_` token to the runtime as `COPILOT_GITHUB_TOKEN`. + +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. + +## Configure the runtime + +The following examples assume the minted token is in `INSTALLATION_TOKEN`. They pass it only to the child runtime and disable fallback to stored user credentials. + +
+TypeScript + +```typescript +import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk"; + +const token = process.env.INSTALLATION_TOKEN; +if (!token) throw new Error("INSTALLATION_TOKEN is required"); + +const client = new CopilotClient({ + connection: RuntimeConnection.forStdio(), + env: { + ...process.env, + COPILOT_GITHUB_TOKEN: token, + }, + useLoggedInUser: false, +}); +``` + +
+
+Python + +```python +import os + +from copilot import CopilotClient, RuntimeConnection + +client = CopilotClient( + connection=RuntimeConnection.for_stdio(), + env={**os.environ, "COPILOT_GITHUB_TOKEN": os.environ["INSTALLATION_TOKEN"]}, + use_logged_in_user=False, +) +``` + +
+
+Go + +```go +package main + +import ( + "log" + "os" + + copilot "github.com/github/copilot-sdk/go" +) + +func main() { + token, ok := os.LookupEnv("INSTALLATION_TOKEN") + if !ok { + log.Fatal("INSTALLATION_TOKEN is required") + } + client := copilot.NewClient(&copilot.ClientOptions{ + Connection: copilot.StdioConnection{}, + Env: append(os.Environ(), "COPILOT_GITHUB_TOKEN="+token), + UseLoggedInUser: copilot.Bool(false), + }) + _ = client +} +``` + +
+
+Rust + +```rust +use github_copilot_sdk::{ClientOptions, Transport}; + +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_use_logged_in_user(false); + drop(options); +} +``` + +
+
+.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, + UseLoggedInUser = false, +}); +``` + +
+
+Java + +```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) + .setUseLoggedInUser(false))) { + // Use the client. +} +``` + +
+ +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. + +## 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. + +## 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. + +## Troubleshooting + +| Symptom | Check | +|---|---| +| `401 Unauthorized` | 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. | +| 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. | + +## Further reading + +* [Authenticate Copilot SDK](./authenticate.md): other authentication methods and priority +* [Generating 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): GitHub App token creation