Skip to content

Commit b8c6308

Browse files
guntripCopilotgfarbgithub-advanced-security[bot]sophietheking
authored
Official Copilot support for org installation S2S tokens (#64319)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Max Goldfarb <gfarb@github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Sophie <29382425+sophietheking@users.noreply.github.com> Co-authored-by: docs-bot <77750099+docs-bot@users.noreply.github.com> Co-authored-by: hubwriter <hubwriter@github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com> Co-authored-by: Pantelis <85220850+Pantelis-Santorinios@users.noreply.github.com> Co-authored-by: Carlin Cherry <61124041+carlincherry@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Copilot-Session: ece718f6-8247-4776-90bd-c960b3b61a7f Copilot-Session: 9a4bfecd-e316-4317-a51d-b3121470bdfc Copilot-Session: 37f9dd70-a938-4033-9446-fc296cdcb01f Copilot-Session: 5ec3aa8f-d7ea-435a-95da-fb99d518dac6
1 parent 42e98ce commit b8c6308

17 files changed

Lines changed: 150 additions & 39 deletions

File tree

-6 Bytes
Loading
4 Bytes
Loading

‎content/billing/how-tos/products/view-productlicense-use.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ You can use the view to answer questions such as:
107107

108108
For information about {% data variables.product.prodname_copilot_short %} allowances and how {% data variables.product.prodname_ai_credits_short %} are pooled across your enterprise, see [AUTOTITLE](/copilot/concepts/billing-and-usage/organizations-and-enterprises/billing).
109109

110+
App attribution is not available in the **AI usage** view. To identify usage from a {% data variables.product.prodname_github_app %} installed on an organization, download an AI usage report. Use the “List app installations for an organization” REST API endpoint and match `app_client_id` in the report to `client_id` in the response. The response’s `app_slug` identifies the app, and `id` identifies the installation. See [AUTOTITLE](/rest/orgs/orgs#list-app-installations-for-an-organization). For report field definitions, see [AUTOTITLE](/billing/reference/billing-reports#usage-report-fields).
111+
110112
For information about {% data variables.product.prodname_AS %} AI-credit billing, see [AUTOTITLE](/billing/concepts/product-billing/github-advanced-security#how-ai-feature-usage-is-billed).
111113

112114
{% endif %}

‎content/billing/reference/billing-reports.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ The usage reports contain the following fields.
6868
| `net_amount` | The billable amount of usage after applying the `discount_amount`. This is the amount that your account will be billed. `gross_amount - discount_amount = net_amount` |
6969
| `username` | The user associated with the usage, if applicable. <br><br> Not included in the `Summarized usage report`. |
7070
| `organization` | The organization associated with the usage, if applicable. |
71+
| {% ifversion copilot %} |
72+
| `app_client_id` | The client ID of the {% data variables.product.prodname_github_app %} associated with usage billed directly to an organization. Use this field with `organization` to identify an app installation. The field is empty for usage attributed to a user, {% data variables.product.prodname_actions %}, other {% data variables.product.company_short %}-owned apps, and usage from before app attribution was available. <br><br>Only available in the `AI usage report` |
73+
| {% endif %} |
7174
| `repository` | The repository associated with the usage, if applicable. |
7275
| `workflow_path` | The path of the {% data variables.product.prodname_actions %} workflow that generated the usage, if applicable. <br><br>Only available in the `Detailed usage report` |
7376
| `cost_center_name` | The cost center associated with the usage, if applicable. |

‎content/copilot/concepts/billing-and-usage/organizations-and-enterprises/billing.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ The cost of an interaction depends on two things: the model and the number of to
2929

3030
Code completions and {% data variables.copilot.next_edit_suggestions %} are **not** billed in {% data variables.product.prodname_ai_credits_short %}. They remain unlimited for all paid plans.
3131

32+
## How is {% data variables.product.prodname_github_app %} usage billed?
33+
34+
A {% data variables.product.prodname_github_app %} installed on an organization can use an installation access token to make {% data variables.product.prodname_copilot_short %} requests without a user signing in. The organization that owns the installation pays for the usage, and the organization’s model policies and spending controls apply.
35+
36+
You cannot create a budget for an individual app or installation. This authentication method does not require the **Allow use of Copilot CLI billed to the organization** policy, which applies to a different authentication path.
37+
38+
For information about approving access, identifying app usage, and blocking an app, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-organization/manage-app-copilot-access).
39+
3240
## How do {% data variables.product.prodname_ai_credits_short %} work?
3341

3442
Each assigned {% data variables.product.prodname_copilot_short %} license comes with a monthly amount of **included {% data variables.product.prodname_ai_credits_short %}**:

‎content/copilot/concepts/billing-and-usage/organizations-and-enterprises/budgets.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ An organization budget caps metered charges for users who receive their {% data
9595

9696
Organization budgets are the only budget option available to organization owners. They can only further restrict usage below any budget set by an enterprise admin, and they cannot override a higher-level budget.
9797

98+
Usage billed directly to an organization from a {% data variables.product.prodname_github_app %} installation counts against the organization budget. You cannot create a budget for an individual app or installation. If **Stop usage when budget limit is reached** is not enabled, the budget only sends alerts and app spending continues after the limit is reached. For information about managing app access, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-organization/manage-app-copilot-access).
99+
98100
If a user receives {% data variables.product.prodname_copilot_short %} licenses from multiple organizations, {% data variables.product.github %} picks one organization at random each billing cycle to bill the seat. This means the user's spend could count against a different organization's budget from month to month, making enforcement unpredictable. To avoid this, ensure each user has a single license through one organization, or use cost center budgets with direct user assignment.
99101

100102
### Enterprise budget

‎content/copilot/how-tos/administer-copilot/manage-for-organization/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ children:
1414
- /manage-plan
1515
- /manage-access
1616
- /manage-policies
17+
- /manage-app-copilot-access
1718
- /add-copilot-cloud-agent
1819
- /configure-runner-for-coding-agent
1920
- /prepare-for-custom-agents
@@ -22,4 +23,3 @@ children:
2223
- /enable-custom-models
2324
contentType: how-tos
2425
---
25-
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
title: Manage GitHub Apps that use your organization's Copilot
3+
shortTitle: Manage GitHub App access
4+
allowTitleToDifferFromFilename: true
5+
intro: "Control which {% data variables.product.prodname_github_apps %} can use your organization's {% data variables.product.prodname_copilot_short %} and attribute their spending."
6+
versions:
7+
fpt: '*'
8+
ghec: '*'
9+
permissions: Organization owners
10+
product: '{% data variables.copilot.copilot_enterprise_short %} or {% data variables.copilot.copilot_business_short %}'
11+
contentType: how-tos
12+
category:
13+
- Manage Copilot for a team
14+
---
15+
16+
> [!NOTE]
17+
> {% data reusables.copilot.org-app-s2s-preview %}
18+
19+
A {% data variables.product.prodname_github_app %} installed on an organization can use its own installation access token to make {% data variables.product.prodname_copilot_short %} requests without a user signing in. The organization that owns the installation pays for the usage.
20+
21+
## Understand access and billing
22+
23+
The app must have the organization **{% data variables.product.prodname_copilot_short %} Requests** permission set to **Read-only**. In this context, **Read-only** does not mean that the app cannot incur costs. The permission authorizes the app to make requests that consume your organization’s {% data variables.product.prodname_ai_credits_short %}.
24+
25+
This authentication method has the following boundaries:
26+
27+
* It applies to apps installed on an organization. Personal account and enterprise installations cannot use this authentication method.
28+
* The app can use only models allowed by your organization’s {% data variables.product.prodname_copilot_short %} policies.
29+
* Your organization’s {% data variables.product.prodname_copilot_short %} billing and spending controls apply. You cannot create a budget for an individual app or installation.
30+
* You do not need to enable the **Allow use of {% data variables.copilot.copilot_cli_short %} billed to the organization** policy. That policy applies to a different authentication path.
31+
32+
This method differs from user authorization, where requests use a user’s identity and are attributed according to that user’s {% data variables.product.prodname_copilot_short %} access. It also differs from {% data variables.product.prodname_actions %}, where workflows use the built-in `GITHUB_TOKEN` and {% data variables.product.prodname_actions %}-specific policies and budgets.
33+
34+
## Review an app before approving access
35+
36+
Only approve apps that you trust to spend your organization’s {% data variables.product.prodname_copilot_short %} usage.
37+
38+
1. Confirm the app’s owner, purpose, and expected usage with the team requesting access.
39+
1. Review all requested organization and repository permissions. Confirm that **{% data variables.product.prodname_copilot_short %} Requests** is an organization permission set to **Read-only**.
40+
1. Review your organization’s model policies and spending controls. If a budget must stop additional usage, make sure **Stop usage when budget limit is reached** is enabled.
41+
1. Install the app or approve its updated permissions.
42+
43+
For instructions on installing an app, see [AUTOTITLE](/apps/using-github-apps/installing-a-github-app-from-a-third-party). If an installed app adds the permission, see [AUTOTITLE](/apps/using-github-apps/approving-updated-permissions-for-a-github-app).
44+
45+
## Identify app usage
46+
47+
App attribution is available in CSV exports, not in the **AI usage** view on {% data variables.product.github %}.
48+
49+
1. Download an AI usage report. See [AUTOTITLE](/billing/how-tos/products/view-productlicense-use#downloading-usage-reports).
50+
1. Find rows with your organization in the `organization` column and a value in `app_client_id`.
51+
1. Use the “List app installations for an organization” REST API endpoint and match `app_client_id` from the report to `client_id` in the response. The `app_slug` value identifies the app. See [AUTOTITLE](/rest/orgs/orgs#list-app-installations-for-an-organization).
52+
53+
The `app_client_id` field is empty for usage attributed to a user, {% data variables.product.prodname_actions %}, other {% data variables.product.company_short %}-owned apps, and historical usage from before app attribution was available. For full field definitions, see [AUTOTITLE](/billing/reference/billing-reports#usage-report-fields).
54+
55+
## Control app spending
56+
57+
Usage from an organization-installed app counts against the organization’s {% data variables.product.prodname_copilot_short %} budget. A budget that only sends alerts does not stop spending. To block requests after the limit is reached, enable **Stop usage when budget limit is reached**.
58+
59+
You cannot create a budget for one app or installation. For more information about organization-level controls, see [AUTOTITLE](/copilot/concepts/billing-and-usage/organizations-and-enterprises/budgets).
60+
61+
## Block an app's access
62+
63+
To stop requests from one app installation, suspend or uninstall it for your organization. This also blocks the installation's access to other organization resources. See [AUTOTITLE](/apps/using-github-apps/reviewing-and-modifying-installed-github-apps#blocking-access).

‎content/copilot/how-tos/copilot-sdk/auth/authenticate.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ For multi-user server mode, pass a per-session `gitHubToken` so each session run
462462

463463
## Disabling auto-login
464464

465-
To prevent the SDK from automatically using stored credentials or `gh` CLI auth, configure it to disable logged-in-user fallback:
465+
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:
466466

467467
{% codetabs %}
468468
{% codetab dotnet %}

‎content/copilot/how-tos/copilot-sdk/auth/server-to-server-tokens.md‎

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,24 @@ The organization's **Allow use of Copilot CLI billed to the organization** polic
3939
4040
For services outside GitHub Actions:
4141
42-
1. Create a GitHub App with the **Copilot Requests** repository permission set to **Read & write**.
43-
1. Install it on the organization that should be billed. The current Copilot permission check requires **All repositories** access.
44-
1. [AUTOTITLE](/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:
42+
1. Create a GitHub App with the **Copilot Requests** organization permission set to **Read-only**.
43+
1. Install it on the organization that usage should be attributed and billed to.
44+
1. [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app) with the Copilot permission:
4545
4646
```json
4747
{
48-
"repository_ids": [123456789],
4948
"permissions": {
50-
"copilot_requests": "write"
49+
"organization_copilot_requests": "read"
5150
}
5251
}
5352
```
5453

55-
1. Pass the resulting `ghs_` token to the runtime as `COPILOT_GITHUB_TOKEN`.
54+
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.
5655

5756
The organization must be enabled for Copilot requests from GitHub App installations. Installation tokens expire after one hour.
5857

59-
> [!WARNING]
60-
> 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.
58+
> [!NOTE]
59+
> 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.
6160
6261
## Configure the runtime
6362

@@ -74,10 +73,7 @@ if (!token) throw new Error("INSTALLATION_TOKEN is required");
7473

7574
const client = new CopilotClient({
7675
connection: RuntimeConnection.forStdio(),
77-
env: {
78-
...process.env,
79-
COPILOT_GITHUB_TOKEN: token,
80-
},
76+
gitHubToken: token,
8177
useLoggedInUser: false,
8278
});
8379
```
@@ -92,7 +88,7 @@ from copilot import CopilotClient, RuntimeConnection
9288

9389
client = CopilotClient(
9490
connection=RuntimeConnection.for_stdio(),
95-
env={**os.environ, "COPILOT_GITHUB_TOKEN": os.environ["INSTALLATION_TOKEN"]},
91+
github_token=os.environ["INSTALLATION_TOKEN"],
9692
use_logged_in_user=False,
9793
)
9894
```
@@ -117,7 +113,7 @@ func main() {
117113
}
118114
client := copilot.NewClient(&copilot.ClientOptions{
119115
Connection: copilot.StdioConnection{},
120-
Env: append(os.Environ(), "COPILOT_GITHUB_TOKEN="+token),
116+
GitHubToken: token,
121117
UseLoggedInUser: copilot.Bool(false),
122118
})
123119
_ = client
@@ -134,7 +130,7 @@ fn main() {
134130
let token = std::env::var("INSTALLATION_TOKEN").expect("INSTALLATION_TOKEN is required");
135131
let options = ClientOptions::new()
136132
.with_transport(Transport::Stdio)
137-
.with_env([("COPILOT_GITHUB_TOKEN", token)])
133+
.with_github_token(token)
138134
.with_use_logged_in_user(false);
139135
drop(options);
140136
}
@@ -144,20 +140,15 @@ fn main() {
144140
{% codetab dotnet %}
145141

146142
```csharp
147-
using System.Collections;
148143
using GitHub.Copilot;
149144

150145
var token = Environment.GetEnvironmentVariable("INSTALLATION_TOKEN")
151146
?? throw new InvalidOperationException("INSTALLATION_TOKEN is required");
152-
var environment = Environment.GetEnvironmentVariables()
153-
.Cast<DictionaryEntry>()
154-
.ToDictionary(entry => (string)entry.Key, entry => entry.Value?.ToString() ?? "");
155-
environment["COPILOT_GITHUB_TOKEN"] = token;
156147

157148
await using var client = new CopilotClient(new CopilotClientOptions
158149
{
159150
Connection = RuntimeConnection.ForStdio(),
160-
Environment = environment,
151+
GitHubToken = token,
161152
UseLoggedInUser = false,
162153
});
163154
```
@@ -168,16 +159,13 @@ await using var client = new CopilotClient(new CopilotClientOptions
168159
```java
169160
import com.github.copilot.CopilotClient;
170161
import com.github.copilot.rpc.CopilotClientOptions;
171-
import java.util.HashMap;
172162
import java.util.Objects;
173163

174-
var environment = new HashMap<>(System.getenv());
175164
var token = Objects.requireNonNull(
176165
System.getenv("INSTALLATION_TOKEN"), "INSTALLATION_TOKEN is required");
177-
environment.put("COPILOT_GITHUB_TOKEN", token);
178166

179167
try (var client = new CopilotClient(new CopilotClientOptions()
180-
.setEnvironment(environment)
168+
.setGitHubToken(token)
181169
.setUseLoggedInUser(false))) {
182170
// Use the client.
183171
}
@@ -186,24 +174,24 @@ try (var client = new CopilotClient(new CopilotClientOptions()
186174
{% endcodetab %}
187175
{% endcodetabs %}
188176

189-
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.
177+
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.
190178

191179
## Refresh tokens
192180

193-
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.
181+
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.
194182

195183
## Billing
196184

197-
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.
185+
Usage is attributed and billed to the organization that owns the GitHub App installation.
198186

199187
## Troubleshooting
200188

201189
| Symptom | Check |
202190
|---|---|
203-
| `401 Unauthorized` | Confirm the organization supports GitHub App installation authentication for Copilot. |
204-
| `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. |
205-
| `403 Forbidden` from the Copilot API | Confirm the token request contains `repository_ids` and `copilot_requests: write`. |
206-
| `403 Forbidden` with the required token request | Confirm the app installation has **All repositories** access, then mint a new token. |
191+
| `401 Unauthorized` | The token may be expired or invalid. Mint a new installation token. |
192+
| `403` stating that Copilot requests with GitHub App installation access tokens are not enabled | Confirm the organization supports GitHub App installation authentication for Copilot. |
193+
| `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. |
194+
| `403 Forbidden` from the Copilot API | Confirm the installation has the organization **Copilot Requests** permission, then mint a new token. |
207195
| Requested model is unavailable | Confirm the organization's Copilot policy allows the model and the bundled runtime supports it. |
208196
| Wrong account billed | Confirm the installation belongs to the intended organization. |
209197

0 commit comments

Comments
 (0)