{"meta":{"title":"GitHub OAuth setup","intro":"Let users authenticate with their GitHub accounts to use Copilot through your application. This supports individual accounts, organization memberships, and enterprise identities.","product":"GitHub Copilot","breadcrumbs":[{"href":"/en/copilot","title":"GitHub Copilot"},{"href":"/en/copilot/how-tos","title":"How-tos"},{"href":"/en/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/en/copilot/how-tos/copilot-sdk/setup","title":"Set up Copilot SDK"},{"href":"/en/copilot/how-tos/copilot-sdk/setup/github-oauth","title":"GitHub OAuth"}],"documentType":"article"},"body":"# GitHub OAuth setup\n\nLet users authenticate with their GitHub accounts to use Copilot through your application. This supports individual accounts, organization memberships, and enterprise identities.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n**Best for:** Multi-user apps, internal tools with org access control, SaaS products, apps where users have GitHub accounts.\n\n## How it works\n\nYou create a GitHub OAuth App (or GitHub App), users authorize it, and you pass their access token to the SDK. Copilot requests are made on behalf of each authenticated user, using their Copilot subscription.\n\n![Diagram: Sequence diagram showing the described process.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-0.png)\n\n**Key characteristics:**\n\n* Each user authenticates with their own GitHub account\n* Copilot usage is billed to each user's subscription\n* Supports GitHub organizations and enterprise accounts\n* Your app never handles model API keys—GitHub manages everything\n\n## Architecture\n\n![Diagram: Flowchart showing the described process.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-1.png)\n\n## Step 1: create a GitHub OAuth app\n\n1. Go to **GitHub Settings → Developer Settings → OAuth Apps → New OAuth App**\n   (or for organizations: **Organization Settings → Developer Settings**)\n\n2. Fill in:\n   * **Application name**: Your app's name\n   * **Homepage URL**: Your app's URL\n   * **Authorization callback URL**: Your OAuth callback endpoint (e.g., `https://yourapp.com/auth/callback`)\n\n3. Note your **Client ID** and generate a **Client Secret**\n\n> **GitHub App vs OAuth App:** Both work. GitHub Apps offer finer-grained permissions and are recommended for new projects. OAuth Apps are simpler to set up. The token flow is the same from the SDK's perspective.\n\n## Step 2: implement the OAuth flow\n\nYour application handles the standard GitHub OAuth flow. Here's the server-side token exchange:\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## Step 3: pass the token to the SDK\n\nCreate an SDK client for each authenticated user, passing their token:\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## Enterprise and organization access\n\nGitHub OAuth naturally supports enterprise scenarios. When users authenticate with GitHub, their org memberships and enterprise associations come along.\n\n![Diagram: Flowchart showing the described process.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-2.png)\n\n### Verify organization membership\n\nAfter OAuth, check that the user belongs to your organization:\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### Enterprise managed users (EMU)\n\nFor GitHub Enterprise Managed Users, the flow is identical—EMU users authenticate through GitHub OAuth like any other user. Their enterprise policies (IP restrictions, SAML SSO) are enforced by GitHub automatically.\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## Supported token types\n\n| Token Prefix  | Source                             | Works?         |\n| ------------- | ---------------------------------- | -------------- |\n| `gho_`        | OAuth user access token            | ✅              |\n| `ghu_`        | GitHub App user access token       | ✅              |\n| `github_pat_` | Fine-grained personal access token | ✅              |\n| `ghp_`        | Classic personal access token      | ❌ (deprecated) |\n\n## Token lifecycle\n\n![Diagram: Flowchart showing the described process.](/assets/images/help/copilot/copilot-sdk/setup-github-oauth-diagram-3.png)\n\n**Important:** Your application is responsible for token storage, refresh, and expiration handling. The SDK uses whatever token you provide—it doesn't manage the OAuth lifecycle.\n\n### Token refresh pattern\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## Multi-user patterns\n\n### One client per user (recommended)\n\nEach user gets their own SDK client with their own token. This provides the strongest isolation.\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### Shared CLI with per-request tokens\n\nFor a lighter resource footprint, you can run a single external CLI server and pass tokens per session. See [Backend services setup](/en/copilot/how-tos/copilot-sdk/setup/backend-services) for this pattern.\n\n## Limitations\n\n| Limitation                                  | Details                                        |\n| ------------------------------------------- | ---------------------------------------------- |\n| **Copilot subscription required**           | Each user needs an active Copilot subscription |\n| **Token management is your responsibility** | Store, refresh, and handle expiration          |\n| **GitHub account required**                 | Users must have GitHub accounts                |\n| **Rate limits per user**                    | Subject to each user's Copilot rate limits     |\n\n## When to move on\n\n| Need                          | Next Guide                                                                       |\n| ----------------------------- | -------------------------------------------------------------------------------- |\n| Users without GitHub accounts | [BYOK (bring your own key)](/en/copilot/how-tos/copilot-sdk/auth/byok)           |\n| Run the SDK on servers        | [Backend services setup](/en/copilot/how-tos/copilot-sdk/setup/backend-services) |\n| Handle many concurrent users  | [Scaling and multi-tenancy](/en/copilot/how-tos/copilot-sdk/setup/scaling)       |\n\n## Next steps\n\n* **[Authentication](/en/copilot/how-tos/copilot-sdk/auth/authenticate)**: Full auth method reference\n* **[Backend services setup](/en/copilot/how-tos/copilot-sdk/setup/backend-services)**: Run the SDK server-side\n* **[Scaling and multi-tenancy](/en/copilot/how-tos/copilot-sdk/setup/scaling)**: Handle many users at scale"}