# GitHub OAuth 设置

让用户使用其GitHub帐户进行身份验证，以便通过应用程序使用Copilot。 这支持个人帐户、组织成员身份和企业标识。

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

**最适合：** 多用户应用、具有组织级访问控制的内部工具、SaaS 产品、用户拥有 GitHub 账户的应用。

## 工作原理

创建GitHub OAuth 应用（或GitHub应用），用户对其进行授权，并将其访问令牌传递给 SDK。 Copilot 使用其 Copilot 订阅代表每个经过身份验证的用户发出请求。

![关系图：显示描述的过程的序列图。](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-0.png)

**主要特征：**

* 每个用户使用自己的GitHub帐户进行身份验证
* Copilot 使用费用将计入每个用户的订阅
* 支持GitHub组织和企业帐户
* 你的应用永远不会处理模型 API 密钥 - GitHub管理所有内容

## Architecture

![图示：显示所述流程的流程图。](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-1.png)

## 步骤 1：创建GitHub OAuth 应用

1. 转到**GitHub设置→开发人员设置→ OAuth 应用→新 OAuth 应用**（或适用于组织：**组织设置→开发人员设置**）

2. 填写：
   * **应用程序名称**：应用的名称
   * **主页 URL**：应用的 URL
   * **授权回调 URL**：您的 OAuth 回调端点（例如 `https://yourapp.com/auth/callback`）

3. 记下 **客户端 ID** 并生成 **客户端密码**

> **GitHub 应用与 OAuth 应用：** 两者都可以。 GitHub应用提供精细的权限，建议用于新项目。 OAuth 应用设置更简单。 从 SDK 的角度来看，令牌流是相同的。

## 步骤 2：实现 OAuth 流

应用程序处理标准GitHub OAuth 流。 下面是服务器端令牌交换：

```typescript
// Server-side: Exchange authorization code for user token
async function handleOAuthCallback(code: string): Promise<string> {
    const response = await fetch("https://github.com/login/oauth/access_token", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            Accept: "application/json",
        },
        body: JSON.stringify({
            client_id: process.env.GITHUB_CLIENT_ID,
            client_secret: process.env.GITHUB_CLIENT_SECRET,
            code,
        }),
    });

    const data = await response.json();
    return data.access_token; // gho_xxxx or ghu_xxxx
}
```

## 步骤 3：将令牌传递给 SDK

为每个经过身份验证的用户创建 SDK 客户端，并传递其令牌：

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient } from "@github/copilot-sdk";

// Create a client for an authenticated user
function createClientForUser(userToken: string): CopilotClient {
    return new CopilotClient({
        gitHubToken: userToken,
        useLoggedInUser: false,  // Don't fall back to CLI login
    });
}

// Usage
const client = createClientForUser("gho_user_access_token");
const session = await client.createSession({
    sessionId: `user-${userId}-session`,
    model: "gpt-5.4",
});

const response = await session.sendAndWait({ prompt: "Hello!" });
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient
from copilot.session import PermissionHandler

def create_client_for_user(user_token: str) -> CopilotClient:
    return CopilotClient({
        "github_token": user_token,
        "use_logged_in_user": False,
    })

# Usage
client = create_client_for_user("gho_user_access_token")
await client.start()

session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-5.4", session_id=f"user-{user_id}-session")

response = await session.send_and_wait("Hello!")
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
func createClientForUser(userToken string) *copilot.Client {
    return copilot.NewClient(&copilot.ClientOptions{
        GitHubToken:     userToken,
        UseLoggedInUser: copilot.Bool(false),
    })
}

// Usage
client := createClientForUser("gho_user_access_token")
client.Start(ctx)
defer client.Stop()

session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
    SessionID: fmt.Sprintf("user-%s-session", userID),
    Model:     "gpt-5.4",
})
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
CopilotClient CreateClientForUser(string userToken) =>
    new CopilotClient(new CopilotClientOptions
    {
        GitHubToken = userToken,
        UseLoggedInUser = false,
    });

// Usage
await using var client = CreateClientForUser("gho_user_access_token");
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = $"user-{userId}-session",
    Model = "gpt-5.4",
});

var response = await session.SendAndWaitAsync(
    new MessageOptions { Prompt = "Hello!" });
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

CopilotClient createClientForUser(String userToken) throws Exception {
    var client = new CopilotClient(new CopilotClientOptions()
        .setGitHubToken(userToken)
        .setUseLoggedInUser(false)
    );
    client.start().get();
    return client;
}

// Usage — use try-with-resources to ensure cleanup
var userId = "user1";
try (var client = createClientForUser("gho_user_access_token")) {
    var session = client.createSession(new SessionConfig()
        .setSessionId(String.format("user-%s-session", userId))
        .setModel("gpt-5.4")
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();

    var response = session.sendAndWait(new MessageOptions()
        .setPrompt("Hello!")).get();
}
```

</div>

</div>

## 企业和组织访问权限

GitHub OAuth 自然支持企业方案。 当用户使用GitHub进行身份验证时，其组织成员资格和企业关联也随之而来。

![图示：显示所述流程的流程图。](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-2.png)

### 验证组织成员身份

OAuth 后，检查用户是否属于组织：

```typescript
async function verifyOrgMembership(
    token: string,
    requiredOrg: string
): Promise<boolean> {
    const response = await fetch("https://api.github.com/user/orgs", {
        headers: { Authorization: `Bearer ${token}` },
    });
    const orgs = await response.json();
    return orgs.some((org: any) => org.login === requiredOrg);
}

// In your auth flow
const token = await handleOAuthCallback(code);
if (!await verifyOrgMembership(token, "my-company")) {
    throw new Error("User is not a member of the required organization");
}
const client = createClientForUser(token);
```

### 企业托管用户（EMU）

对于GitHub企业托管用户，流是相同的 — EMU 用户像任何其他用户一样通过 GitHub OAuth 进行身份验证。 其企业策略（IP 限制、SAML SSO）由 GitHub 自动强制执行。

```typescript
// No special SDK configuration needed for EMU
// Enterprise policies are enforced server-side by GitHub
const client = new CopilotClient({
    gitHubToken: emuUserToken,  // Works the same as regular tokens
    useLoggedInUser: false,
});
```

## 支持的令牌类型

| 令牌前缀          | 来源             | 可以用吗？ |
| ------------- | -------------- | ----- |
| `gho_`        | OAuth 用户访问令牌   | ✅     |
| `ghu_`        | GitHub应用用户访问令牌 | ✅     |
| `github_pat_` | 细粒度的个人访问令牌     | ✅     |
| `ghp_`        | 经典个人访问令牌       |       |
| ❌（已弃用）        |                |       |

## 令牌生命周期

![图示：显示所述流程的流程图。](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-3.png)

**重要：** 应用程序负责令牌存储、刷新和过期处理。 SDK 使用你提供的任何令牌 -- 它不管理 OAuth 生命周期。

### 令牌刷新模式

```typescript
async function getOrRefreshToken(userId: string): Promise<string> {
    const stored = await tokenStore.get(userId);

    if (stored && !isExpired(stored)) {
        return stored.accessToken;
    }

    if (stored?.refreshToken) {
        const refreshed = await refreshGitHubToken(stored.refreshToken);
        await tokenStore.set(userId, refreshed);
        return refreshed.accessToken;
    }

    throw new Error("User must re-authenticate");
}
```

## 多用户模式

### 每个用户一个客户端（建议）

每个用户使用自己的令牌获取自己的 SDK 客户端。 这提供最强的隔离。

```typescript
const clients = new Map<string, CopilotClient>();

function getClientForUser(userId: string, token: string): CopilotClient {
    if (!clients.has(userId)) {
        clients.set(userId, new CopilotClient({
            gitHubToken: token,
            useLoggedInUser: false,
        }));
    }
    return clients.get(userId)!;
}
```

### 共享 CLI，每请求使用不同令牌

为了减小资源占用，你可以运行单个外部 CLI 服务器，并按会话传递令牌。 有关此模式，请参阅 [后端服务设置](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/backend-services) 。

## 局限性

| Limitation        | 详细信息                    |
| ----------------- | ----------------------- |
| **需要 Copilot 订阅** | 每个用户都需要一个有效的 Copilot 订阅 |
| **令牌管理是你的责任**     | 存储、刷新和处理过期              |
| 需要**GitHub帐户**    | 用户必须具有GitHub帐户          |
| **每个用户的速率限制**     | 取决于各用户的 Copilot 速率限制    |

## 何时继续

| 需要                                                                                       | 下一篇指南 |
| ---------------------------------------------------------------------------------------- | ----- |
| 没有GitHub帐户的用户                                                                            |       |
| [BYOK （自带密钥）](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/auth/byok)         |       |
| 在服务器上运行 SDK                                                                              |       |
| [后端服务设置](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/backend-services) |       |
| 处理多个并发用户                                                                                 |       |
| [缩放和多租户](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/scaling)          |       |

## 后续步骤

* **[Authentication](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/auth/authenticate)**：完整身份验证方法参考
* **[后端服务设置](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/backend-services)**：在服务器端运行 SDK
* **[缩放和多租户](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/setup/scaling)**：大规模处理大量用户