{"meta":{"title":"GitHub OAuth 설정","intro":"사용자가 애플리케이션을 통해 Copilot 사용하도록 GitHub 계정으로 인증할 수 있습니다. 개별 계정, 조직 멤버 자격 및 엔터프라이즈 ID를 지원합니다.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ko/copilot","title":"GitHub Copilot"},{"href":"/ko/copilot/how-tos","title":"방법"},{"href":"/ko/copilot/how-tos/copilot-sdk","title":"코필로트 SDK"},{"href":"/ko/copilot/how-tos/copilot-sdk/setup","title":"Copilot SDK 설정"},{"href":"/ko/copilot/how-tos/copilot-sdk/setup/github-oauth","title":"GitHub OAuth (로그인 인증 프로토콜)"}],"documentType":"article"},"body":"# GitHub OAuth 설정\n\n사용자가 애플리케이션을 통해 Copilot 사용하도록 GitHub 계정으로 인증할 수 있습니다. 개별 계정, 조직 멤버 자격 및 엔터프라이즈 ID를 지원합니다.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n**Best for:** 다중 사용자 앱, 조직 액세스 제어가 있는 내부 도구, SaaS 제품, 사용자가 GitHub 계정이 있는 앱.\n\n## 작동 방식\n\nGitHub OAuth 앱(또는 GitHub 앱을 만들고, 사용자가 권한을 부여하고, 해당 액세스 토큰을 SDK에 전달합니다. Copilot 요청은 Copilot 구독을 사용하여 인증된 각 사용자를 대신하여 이루어집니다.\n\n![다이어그램: 설명된 프로세스를 보여 주는 시퀀스 다이어그램](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-0.png)\n\n**주요 특징:**\n\n* 각 사용자는 자신의 GitHub 계정으로 인증합니다.\n* Copilot 사용량은 각 사용자의 구독에 청구됩니다.\n* GitHub 조직 및 엔터프라이즈 계정 지원\n* 앱은 모델 API 키를 처리하지 않습니다. GitHub 모든 것을 관리합니다.\n\n## 아키텍처\n\n![다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-1.png)\n\n## 1단계: GitHub OAuth 앱 만들기\n\n1. **GitHub 설정 → 개발자 설정 → OAuth 앱 → 새 OAuth 앱**(또는 조직: \\*\\* 개발자 설정 → 구성 설정\\*\\*)으로 이동합니다.\n\n2. 다음을 입력합니다.\n   * **애플리케이션 이름**: 앱 이름\n   * **홈페이지 URL**: 앱의 URL\n   * **권한 부여 콜백 URL**: OAuth 콜백 엔드포인트(예: `https://yourapp.com/auth/callback`)\n\n3. **클라이언트 ID**를 확인하고 **클라이언트 암호를** 생성합니다.\n\n> **GitHub 앱과 OAuth App:** 모두 작동합니다. GitHub 앱은 세분화된 권한을 제공하며 새 프로젝트에 권장됩니다. OAuth 앱은 설정하는 것이 더 간단합니다. 토큰 흐름은 SDK의 관점에서 동일합니다.\n\n## 2단계: OAuth 흐름 구현\n\n애플리케이션은 표준 GitHub OAuth 흐름을 처리합니다. 서버 쪽 토큰 교환은 다음과 같습니다.\n\n```typescript\n// Server-side: Exchange authorization code for user token\nasync function handleOAuthCallback(code: string): Promise<string> {\n    const response = await fetch(\"https://github.com/login/oauth/access_token\", {\n        method: \"POST\",\n        headers: {\n            \"Content-Type\": \"application/json\",\n            Accept: \"application/json\",\n        },\n        body: JSON.stringify({\n            client_id: process.env.GITHUB_CLIENT_ID,\n            client_secret: process.env.GITHUB_CLIENT_SECRET,\n            code,\n        }),\n    });\n\n    const data = await response.json();\n    return data.access_token; // gho_xxxx or ghu_xxxx\n}\n```\n\n## 3단계: SDK에 토큰 전달\n\n인증된 각 사용자에 대한 SDK 클라이언트를 만들고 해당 토큰을 전달합니다.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\n// Create a client for an authenticated user\nfunction createClientForUser(userToken: string): CopilotClient {\n    return new CopilotClient({\n        gitHubToken: userToken,\n        useLoggedInUser: false,  // Don't fall back to CLI login\n    });\n}\n\n// Usage\nconst client = createClientForUser(\"gho_user_access_token\");\nconst session = await client.createSession({\n    sessionId: `user-${userId}-session`,\n    model: \"gpt-5.4\",\n});\n\nconst response = await session.sendAndWait({ prompt: \"Hello!\" });\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\n\ndef create_client_for_user(user_token: str) -> CopilotClient:\n    return CopilotClient({\n        \"github_token\": user_token,\n        \"use_logged_in_user\": False,\n    })\n\n# Usage\nclient = create_client_for_user(\"gho_user_access_token\")\nawait client.start()\n\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"gpt-5.4\", session_id=f\"user-{user_id}-session\")\n\nresponse = await session.send_and_wait(\"Hello!\")\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nfunc createClientForUser(userToken string) *copilot.Client {\n    return copilot.NewClient(&copilot.ClientOptions{\n        GitHubToken:     userToken,\n        UseLoggedInUser: copilot.Bool(false),\n    })\n}\n\n// Usage\nclient := createClientForUser(\"gho_user_access_token\")\nclient.Start(ctx)\ndefer client.Stop()\n\nsession, _ := client.CreateSession(ctx, &copilot.SessionConfig{\n    SessionID: fmt.Sprintf(\"user-%s-session\", userID),\n    Model:     \"gpt-5.4\",\n})\nresponse, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"Hello!\"})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nCopilotClient CreateClientForUser(string userToken) =>\n    new CopilotClient(new CopilotClientOptions\n    {\n        GitHubToken = userToken,\n        UseLoggedInUser = false,\n    });\n\n// Usage\nawait using var client = CreateClientForUser(\"gho_user_access_token\");\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    SessionId = $\"user-{userId}-session\",\n    Model = \"gpt-5.4\",\n});\n\nvar response = await session.SendAndWaitAsync(\n    new MessageOptions { Prompt = \"Hello!\" });\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nCopilotClient createClientForUser(String userToken) throws Exception {\n    var client = new CopilotClient(new CopilotClientOptions()\n        .setGitHubToken(userToken)\n        .setUseLoggedInUser(false)\n    );\n    client.start().get();\n    return client;\n}\n\n// Usage — use try-with-resources to ensure cleanup\nvar userId = \"user1\";\ntry (var client = createClientForUser(\"gho_user_access_token\")) {\n    var session = client.createSession(new SessionConfig()\n        .setSessionId(String.format(\"user-%s-session\", userId))\n        .setModel(\"gpt-5.4\")\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n    ).get();\n\n    var response = session.sendAndWait(new MessageOptions()\n        .setPrompt(\"Hello!\")).get();\n}\n```\n\n</div>\n\n</div>\n\n## 엔터프라이즈 및 조직 액세스\n\nGitHub OAuth는 자연스럽게 엔터프라이즈 시나리오를 지원합니다. 사용자가 GitHub 인증하면 조직 멤버 자격 및 엔터프라이즈 연결이 함께 제공됩니다.\n\n![다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-2.png)\n\n### 조직 멤버 자격 확인\n\nOAuth 후 사용자가 조직에 속하는지 확인합니다.\n\n```typescript\nasync function verifyOrgMembership(\n    token: string,\n    requiredOrg: string\n): Promise<boolean> {\n    const response = await fetch(\"https://api.github.com/user/orgs\", {\n        headers: { Authorization: `Bearer ${token}` },\n    });\n    const orgs = await response.json();\n    return orgs.some((org: any) => org.login === requiredOrg);\n}\n\n// In your auth flow\nconst token = await handleOAuthCallback(code);\nif (!await verifyOrgMembership(token, \"my-company\")) {\n    throw new Error(\"User is not a member of the required organization\");\n}\nconst client = createClientForUser(token);\n```\n\n### EMU(엔터프라이즈 관리형 사용자)\n\nGitHub 엔터프라이즈 관리 사용자의 경우 흐름이 동일합니다. EMU 사용자는 다른 사용자와 마찬가지로 GitHub OAuth를 통해 인증합니다. 해당 엔터프라이즈 정책(IP 제한, SAML SSO)은 GitHub 자동으로 적용됩니다.\n\n```typescript\n// No special SDK configuration needed for EMU\n// Enterprise policies are enforced server-side by GitHub\nconst client = new CopilotClient({\n    gitHubToken: emuUserToken,  // Works the same as regular tokens\n    useLoggedInUser: false,\n});\n```\n\n## 지원되는 토큰 형식\n\n| 토큰 접두사          | Source              | 작동합니까? |\n| --------------- | ------------------- | ------ |\n| `gho_`          | OAuth 사용자 액세스 토큰    | ✅      |\n| `ghu_`          | GitHub 앱 사용자 액세스 토큰 | ✅      |\n| `github_pat_`   | 세분화된 개인용 액세스 토큰     | ✅      |\n| `ghp_`          | 클래식 개인용 액세스 토큰      |        |\n| ❌(더 이상 사용되지 않음) |                     |        |\n\n## 토큰 수명 주기\n\n![다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-3.png)\n\n**중요:** 애플리케이션은 토큰 스토리지, 새로 고침 및 만료 처리를 담당합니다. SDK는 사용자가 제공하는 토큰을 사용하며 OAuth 수명 주기를 관리하지 않습니다.\n\n### 토큰 새로 고침 패턴\n\n```typescript\nasync function getOrRefreshToken(userId: string): Promise<string> {\n    const stored = await tokenStore.get(userId);\n\n    if (stored && !isExpired(stored)) {\n        return stored.accessToken;\n    }\n\n    if (stored?.refreshToken) {\n        const refreshed = await refreshGitHubToken(stored.refreshToken);\n        await tokenStore.set(userId, refreshed);\n        return refreshed.accessToken;\n    }\n\n    throw new Error(\"User must re-authenticate\");\n}\n```\n\n## 다중 사용자 패턴\n\n### 사용자당 하나의 클라이언트(권장)\n\n각 사용자는 자신의 토큰을 사용하여 자신의 SDK 클라이언트를 가져옵니다. 이렇게 하면 가장 강력한 격리가 제공됩니다.\n\n```typescript\nconst clients = new Map<string, CopilotClient>();\n\nfunction getClientForUser(userId: string, token: string): CopilotClient {\n    if (!clients.has(userId)) {\n        clients.set(userId, new CopilotClient({\n            gitHubToken: token,\n            useLoggedInUser: false,\n        }));\n    }\n    return clients.get(userId)!;\n}\n```\n\n### 요청별 토큰이 있는 공유 CLI\n\n리소스 사용 공간을 줄이기 위해 단일 외부 CLI 서버를 실행하고 세션당 토큰을 전달할 수 있습니다. 이 패턴은 [백 엔드 서비스 설정](/ko/copilot/how-tos/copilot-sdk/setup/backend-services)을 참조하세요.\n\n## Limitations\n\n| Limitation             | Details                       |\n| ---------------------- | ----------------------------- |\n| **Copilot 구독 필요**      | 각 사용자에게 활성 Copilot 구독이 필요합니다. |\n| **토큰 관리는 사용자의 책임입니다.** | 만료 저장, 새로 고침 및 처리             |\n| **GitHub 계정이 필요합니다**   | 사용자에게 GitHub 계정이 있어야 합니다.     |\n| **사용자당 속도 제한**         | 각 사용자의 Copilot 속도 제한이 적용됩니다.  |\n\n## 이동 시기\n\n| 필요                                                                    | 다음 가이드 |\n| --------------------------------------------------------------------- | ------ |\n| GitHub 계정이 없는 사용자                                                     |        |\n| [BYOK(사용자 고유의 키 가져오기)](/ko/copilot/how-tos/copilot-sdk/auth/byok)     |        |\n| 서버에서 SDK 실행                                                           |        |\n| [백 엔드 서비스 설정](/ko/copilot/how-tos/copilot-sdk/setup/backend-services) |        |\n| 많은 동시 사용자 처리                                                          |        |\n| [확장성 및 멀티 테넌시](/ko/copilot/how-tos/copilot-sdk/setup/scaling)         |        |\n\n## 다음 단계\n\n* **[인증](/ko/copilot/how-tos/copilot-sdk/auth/authenticate)**: 전체 인증 메서드 참조\n* **[백 엔드 서비스 설정](/ko/copilot/how-tos/copilot-sdk/setup/backend-services)**: SDK 서버 쪽 실행\n* **[확장성 및 멀티 테넌시](/ko/copilot/how-tos/copilot-sdk/setup/scaling)**: 대규모 사용자 처리하기"}