Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |

Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion docs/auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
3 changes: 3 additions & 0 deletions docs/auth/authenticate.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
205 changes: 205 additions & 0 deletions docs/auth/server-to-server-tokens.md
Original file line number Diff line number Diff line change
@@ -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.

<details open>
<summary><strong>TypeScript</strong></summary>

```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,
});
```

</details>
<details>
<summary><strong>Python</strong></summary>

```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,
)
```

</details>
<details>
<summary><strong>Go</strong></summary>

```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
}
```

</details>
<details>
<summary><strong>Rust</strong></summary>

```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);
}
```

</details>
<details>
<summary><strong>.NET</strong></summary>

```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<DictionaryEntry>()
.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,
});
```

</details>
<details>
<summary><strong>Java</strong></summary>

```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.
}
```

</details>

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
Loading