Skip to content

Commit 7f1f847

Browse files
patnikoSteveSandersonMSCopilot
authored
docs: add server-to-server token guide (#2005)
* docs: add server-to-server token guide Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2a84bd21-23e5-4358-96f1-f343030bb869 * docs: tighten server-to-server auth guidance (#2125) * docs: tighten server-to-server auth guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add per-language server auth examples Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: clarify installation billing attribution Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: restore server auth troubleshooting cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Steve Sanderson <SteveSandersonMS@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2a84bd21-23e5-4358-96f1-f343030bb869
1 parent aa4e707 commit 7f1f847

4 files changed

Lines changed: 212 additions & 2 deletions

File tree

docs/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Welcome to the GitHub Copilot SDK docs. Whether you're building your first Copil
88
|---|---|
99
| **Build my first app** | [Getting Started](./getting-started.md)—end-to-end tutorial with streaming & custom tools |
1010
| **Set up for production** | [Setup Guides](./setup/README.md)—architecture, deployment patterns, scaling |
11-
| **Configure authentication** | [Authentication](./auth/README.md)—GitHub OAuth, environment variables, BYOK |
11+
| **Configure authentication** | [Authentication](./auth/README.md)—GitHub OAuth, server-to-server authentication, environment variables, BYOK |
1212
| **Add features to my app** | [Features](./features/README.md)—hooks, custom agents, MCP, skills, and more |
1313
| **Debug an issue** | [Troubleshooting](./troubleshooting/debugging.md)—common problems and solutions |
1414

@@ -35,6 +35,7 @@ How to configure and deploy the SDK for your use case.
3535
Configuring how users and services authenticate with Copilot.
3636

3737
* [Authentication Overview](./auth/README.md): methods, priority order, and examples
38+
* [Server-to-server authentication](./auth/server-to-server-tokens.md): use GitHub Actions or GitHub App installation tokens for organization-attributed automation
3839
* [Bring Your Own Key (BYOK)](./auth/byok.md): use your own API keys from OpenAI, Azure, Anthropic, and more
3940

4041
### [Features](./features/README.md)

docs/auth/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
Choose the authentication method that best fits your deployment scenario for the GitHub Copilot SDK.
44

55
* [Authenticate Copilot SDK](authenticate.md): methods, priority order, and examples
6+
* [Server-to-server authentication](server-to-server-tokens.md): use GitHub Actions or GitHub App installation tokens for organization-attributed automation
67
* [Bring your own key (BYOK)](./byok.md): use your own API keys from OpenAI, Azure, Anthropic, and more
78

89
## Authentication priority
910

10-
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.
11+
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.
1112

1213
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).

docs/auth/authenticate.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The GitHub Copilot SDK supports multiple authentication methods to fit different
99
| [GitHub Signed-in User](#github-signed-in-user) | Interactive apps where users sign in with GitHub | Yes |
1010
| [OAuth GitHub App](#oauth-github-app) | Apps acting on behalf of users via OAuth | Yes |
1111
| [Environment Variables](#environment-variables) | CI/CD, automation, server-to-server | Yes |
12+
| [Server-to-server authentication](./server-to-server-tokens.md) | Organization-attributed automation and direct organization billing | No user subscription; organization policy required |
1213
| [BYOK (Bring Your Own Key)](./byok.md) | Using your own API keys (Azure AI Foundry, OpenAI, and more) | No |
1314

1415
## GitHub signed-in user
@@ -236,6 +237,8 @@ client.start().get();
236237

237238
For automation, CI/CD pipelines, and server-to-server scenarios, you can authenticate using environment variables.
238239

240+
For organization-attributed automation that should not use a user's personal access token, see [Server-to-server authentication](./server-to-server-tokens.md).
241+
239242
**Supported environment variables (in priority order):**
240243
1. `COPILOT_GITHUB_TOKEN` - Recommended for explicit Copilot usage
241244
1. `GH_TOKEN` - GitHub CLI compatible
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Server-to-server authentication
2+
3+
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.
4+
5+
## GitHub Actions
6+
7+
For workflows in an organization-owned repository, grant the built-in token permission to make Copilot requests:
8+
9+
```yaml
10+
permissions:
11+
contents: read
12+
copilot-requests: write
13+
14+
jobs:
15+
copilot:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v6
19+
- run: your-application
20+
env:
21+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
```
23+
24+
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).
25+
26+
## Other services and CI systems
27+
28+
For services outside GitHub Actions:
29+
30+
1. Create a GitHub App with the **Copilot Requests** repository permission set to **Read & write**.
31+
1. Install it on the organization that should be billed. The current Copilot permission check requires **All repositories** access.
32+
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:
33+
34+
```json
35+
{
36+
"repository_ids": [123456789],
37+
"permissions": {
38+
"copilot_requests": "write"
39+
}
40+
}
41+
```
42+
43+
1. Pass the resulting `ghs_` token to the runtime as `COPILOT_GITHUB_TOKEN`.
44+
45+
The organization must be enabled for Copilot requests from GitHub App installations. Installation tokens expire after one hour.
46+
47+
> [!WARNING]
48+
> 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.
49+
50+
## Configure the runtime
51+
52+
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.
53+
54+
<details open>
55+
<summary><strong>TypeScript</strong></summary>
56+
57+
```typescript
58+
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
59+
60+
const token = process.env.INSTALLATION_TOKEN;
61+
if (!token) throw new Error("INSTALLATION_TOKEN is required");
62+
63+
const client = new CopilotClient({
64+
connection: RuntimeConnection.forStdio(),
65+
env: {
66+
...process.env,
67+
COPILOT_GITHUB_TOKEN: token,
68+
},
69+
useLoggedInUser: false,
70+
});
71+
```
72+
73+
</details>
74+
<details>
75+
<summary><strong>Python</strong></summary>
76+
77+
```python
78+
import os
79+
80+
from copilot import CopilotClient, RuntimeConnection
81+
82+
client = CopilotClient(
83+
connection=RuntimeConnection.for_stdio(),
84+
env={**os.environ, "COPILOT_GITHUB_TOKEN": os.environ["INSTALLATION_TOKEN"]},
85+
use_logged_in_user=False,
86+
)
87+
```
88+
89+
</details>
90+
<details>
91+
<summary><strong>Go</strong></summary>
92+
93+
```go
94+
package main
95+
96+
import (
97+
"log"
98+
"os"
99+
100+
copilot "github.com/github/copilot-sdk/go"
101+
)
102+
103+
func main() {
104+
token, ok := os.LookupEnv("INSTALLATION_TOKEN")
105+
if !ok {
106+
log.Fatal("INSTALLATION_TOKEN is required")
107+
}
108+
client := copilot.NewClient(&copilot.ClientOptions{
109+
Connection: copilot.StdioConnection{},
110+
Env: append(os.Environ(), "COPILOT_GITHUB_TOKEN="+token),
111+
UseLoggedInUser: copilot.Bool(false),
112+
})
113+
_ = client
114+
}
115+
```
116+
117+
</details>
118+
<details>
119+
<summary><strong>Rust</strong></summary>
120+
121+
```rust
122+
use github_copilot_sdk::{ClientOptions, Transport};
123+
124+
fn main() {
125+
let token = std::env::var("INSTALLATION_TOKEN").expect("INSTALLATION_TOKEN is required");
126+
let options = ClientOptions::new()
127+
.with_transport(Transport::Stdio)
128+
.with_env([("COPILOT_GITHUB_TOKEN", token)])
129+
.with_use_logged_in_user(false);
130+
drop(options);
131+
}
132+
```
133+
134+
</details>
135+
<details>
136+
<summary><strong>.NET</strong></summary>
137+
138+
```csharp
139+
using System.Collections;
140+
using GitHub.Copilot;
141+
142+
var token = Environment.GetEnvironmentVariable("INSTALLATION_TOKEN")
143+
?? throw new InvalidOperationException("INSTALLATION_TOKEN is required");
144+
var environment = Environment.GetEnvironmentVariables()
145+
.Cast<DictionaryEntry>()
146+
.ToDictionary(entry => (string)entry.Key, entry => entry.Value?.ToString() ?? "");
147+
environment["COPILOT_GITHUB_TOKEN"] = token;
148+
149+
await using var client = new CopilotClient(new CopilotClientOptions
150+
{
151+
Connection = RuntimeConnection.ForStdio(),
152+
Environment = environment,
153+
UseLoggedInUser = false,
154+
});
155+
```
156+
157+
</details>
158+
<details>
159+
<summary><strong>Java</strong></summary>
160+
161+
```java
162+
import com.github.copilot.CopilotClient;
163+
import com.github.copilot.rpc.CopilotClientOptions;
164+
import java.util.HashMap;
165+
import java.util.Objects;
166+
167+
var environment = new HashMap<>(System.getenv());
168+
var token = Objects.requireNonNull(
169+
System.getenv("INSTALLATION_TOKEN"), "INSTALLATION_TOKEN is required");
170+
environment.put("COPILOT_GITHUB_TOKEN", token);
171+
172+
try (var client = new CopilotClient(new CopilotClientOptions()
173+
.setEnvironment(environment)
174+
.setUseLoggedInUser(false))) {
175+
// Use the client.
176+
}
177+
```
178+
179+
</details>
180+
181+
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.
182+
183+
## Refresh tokens
184+
185+
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.
186+
187+
## Billing
188+
189+
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.
190+
191+
## Troubleshooting
192+
193+
| Symptom | Check |
194+
|---|---|
195+
| `401 Unauthorized` | Confirm the organization supports GitHub App installation authentication for Copilot. |
196+
| `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. |
197+
| `403 Forbidden` from the Copilot API | Confirm the token request contains `repository_ids` and `copilot_requests: write`. |
198+
| `403 Forbidden` with the required token request | Confirm the app installation has **All repositories** access, then mint a new token. |
199+
| Requested model is unavailable | Confirm the organization's Copilot policy allows the model and the bundled runtime supports it. |
200+
| Wrong account billed | Confirm the installation belongs to the intended organization. |
201+
202+
## Further reading
203+
204+
* [Authenticate Copilot SDK](./authenticate.md): other authentication methods and priority
205+
* [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

0 commit comments

Comments
 (0)