# 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