Skip to content

fix(github_copilot): disable shared device login on the proxy - #45697

Open
yassin-berriai wants to merge 2 commits into
mainfrom
litellm_github_copilot_proxy_per_user_only
Open

yassin-berriai wants to merge 2 commits into
mainfrom
litellm_github_copilot_proxy_per_user_only

Conversation

@yassin-berriai

@yassin-berriai yassin-berriai commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • A gateway GitHub Copilot model with no per-user credential falls back to shared device login
  • Device login needs a human at a terminal, so gateway workers block or drop the deployment
  • The dashboard still offers "Shared device login" as a credential auth type

How it solves it:

  • Proxy startup turns off shared device login in every worker
  • Shared-mode gateway requests return a 401 pointing at Per-user GitHub OAuth
  • The token directory is never read or created on the gateway
  • The dashboard only offers Per-user GitHub OAuth for GitHub Copilot
  • Direct Python SDK calls keep shared device login unchanged

Intentional product change: gateways that relied on a shared access-token file for GitHub Copilot now get a 401 on those models until the admin attaches a Per-user GitHub OAuth credential and each user clicks Connect under LLM Credentials. Shared login is too risky on the gateway because a missing token makes workers wait on a human device code

User Flow

Before: an admin adds a GitHub Copilot model without a per-user credential, and the gateway tries to run GitHub's device login inside its workers

  1. Admin adds github_copilot/gpt-4.1 with no credential at https://litellm-domain/ui/?page=models
  2. The dashboard offers "Shared device login" as an auth type for the GitHub Copilot credential
  3. A user sends POST https://litellm-domain/v1/chat/completions for that model
  4. The gateway reads its token directory and, with no token on disk, tries to start a terminal device login nobody can finish

After: the same model fails fast with a clear 401, and per-user OAuth is the only gateway setup

  1. Admin adds github_copilot/gpt-4.1 with no credential at https://litellm-domain/ui/?page=models
  2. The credential form only offers "Per-user GitHub OAuth"
  3. A user sends POST https://litellm-domain/v1/chat/completions or /v1/messages for that model
  4. They get HTTP 401 "GitHub Copilot shared device login is disabled on the LiteLLM proxy. Create an LLM credential with Auth Type 'Per-user GitHub OAuth'...", and the token directory is untouched

Linear ticket

Resolves LIT-9306

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Proxy config used on both sides, with GITHUB_COPILOT_TOKEN_DIR pointed at a directory holding placeholder access-token and api-key.json files:

model_list:
  - model_name: ghc-shared-chat
    litellm_params:
      model: github_copilot/gpt-4.1
  - model_name: ghc-shared-messages
    litellm_params:
      model: github_copilot/claude-sonnet-5.5
  - model_name: ghc-per-user
    litellm_params:
      model: github_copilot/gpt-4.1
      litellm_credential_name: ghc-per-user-credential
      github_copilot_auth_type: per_user_oauth

Before (merge base 4cb47ed)

Placeholder token files on disk

  1. curl -i -X POST https://litellm-domain/v1/chat/completions -d '{"model":"ghc-shared-chat","messages":[{"role":"user","content":"ping"}]}'
  2. HTTP/1.1 400 Bad Request with Github_copilotException - bad request: Authorization header is badly formatted, because the gateway read the shared token file and sent it to GitHub. /v1/messages on ghc-shared-messages returns the same 400
  3. stat shows the api-key.json atime moved from 1791589739 to 1791590357, so the gateway read the shared token directory

Empty token directory

  1. Startup logs that the token files are missing and that shared device-code login needs a human, then drops both shared deployments
  2. The same two curls return HTTP/1.1 400 Bad Request with There are no healthy deployments for this model

In both runs the unconnected per-user model returns the same Connect 401 as After

After (13ae055)

Shared /v1/chat/completions

  1. curl -i -X POST https://litellm-domain/v1/chat/completions -d '{"model":"ghc-shared-chat","messages":[{"role":"user","content":"ping"}]}'
  2. HTTP/1.1 401 Unauthorized with {"error":{"message":"litellm.AuthenticationError: GitHub Copilot shared device login is disabled on the LiteLLM proxy. Create an LLM credential with Auth Type 'Per-user GitHub OAuth' and reference it from the deployment with litellm_credential_name ...","type":"authentication_error","code":"401"}}

Shared /v1/messages

  1. curl -i -X POST https://litellm-domain/v1/messages -d '{"model":"ghc-shared-messages","max_tokens":50,"messages":[{"role":"user","content":"ping"}]}'
  2. HTTP/1.1 401 Unauthorized with {"type":"error","error":{"type":"authentication_error","message":"litellm.AuthenticationError: GitHub Copilot shared device login is disabled on the LiteLLM proxy. ..."}}

Per-user model, user not connected

  1. curl -i -X POST https://litellm-domain/v1/chat/completions -d '{"model":"ghc-per-user","messages":[{"role":"user","content":"ping"}]}'
  2. HTTP/1.1 401 Unauthorized with Connect GitHub Copilot for credential 'ghc-per-user-credential' in the LiteLLM UI (LLM Credentials), unchanged from main

Token directory

  1. stat on the token directory and both files before starting the proxy and after the three requests
  2. mtime, atime, size and inode are identical, so the gateway never read or wrote them

Type

🐛 Bug Fix

Link to Devin session: https://app.devin.ai/sessions/453c40b054f240f1bf0e4512da9a9aae
Open in Devin Desktop: https://app.devin.ai/desktop/session/453c40b054f240f1bf0e4512da9a9aae?variant=devin
Requested by: @yassin-berriai

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Critical impact] Disables shared device login for GitHub Copilot on the proxy.

Fix the team-admin setup path and satisfy the repository’s release, testing, and code requirements before merging

Findings

  1. P1 Team admins save unusable models ▶
  2. P1 Breaking change lacks title marker ▶
  3. P2 Required live proof is incomplete ▶
  4. P2 Provider logic enters shared code ▶
  5. P2 Tests miss required variable annotations ▶

Summary

This PR disables shared GitHub Copilot authentication during proxy startup, returns 401 for shared requests, and makes per-user OAuth the dashboard default

  • Proxy workers reject GitHub Copilot shared device login.
  • GitHub Copilot setup offers only per-user OAuth.

Reviews (1) · Last reviewed commit: "fix(github-copilot): disable proxy share..." · Reviewed by Greptile

"Each LiteLLM user connects their own GitHub account from LLM Credentials, and their requests use their own GitHub Copilot access. Users who have not connected get a 401.",
fieldKeys: [GITHUB_COPILOT_AUTH_TYPE_KEY],
requiredFieldKeys: [GITHUB_COPILOT_AUTH_TYPE_KEY],
hiddenFieldKeys: ["api_base", "api_key"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Team admins save unusable models

Removing the shared option leaves team admins with no available auth type. The form then shows raw credentials and skips its credential-required check. Models saved without a per-user credential return 401 because shared authentication is disabled. Keep credential selection required even when the user cannot create credentials

Knowledge Base Used: Dashboard and enterprise UI


from litellm.llms.github_copilot.authenticator import disable_github_copilot_shared_login

disable_github_copilot_shared_login()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Breaking change lacks title marker

Existing shared-token deployments now return 401, but the title lacks the breaking-change marker required by the repository. Change it to fix(github_copilot)!: before merging so release notes flag the upgrade impact

Rule Used: What: When a PR changes behavior that existing users rely on, the PR title must mark it breaking with ! after the type or scope (e.g. fix(mcp)!: ..., feat!: ...), and the PR description must have a short "Breaking change" note saying who is aff... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


from litellm.llms.github_copilot.authenticator import disable_github_copilot_shared_login

disable_github_copilot_shared_login()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Required live proof is incomplete

The supplied proof shows rejected requests but no connected-user success, Responses or embeddings calls, or dashboard setup. The repository requires live proof across affected endpoints and both success and failure paths. Add those cases before merging

Rule Used: Flag if the PR has no proof of e2e testing (if e2e testing is applicable here. If it's like an AGENTS.md change or something then probably no need to have e2e test proof) that either doesn't exist, claims that the box that it was trying to run in doe... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread litellm/main.py
Comment on lines +2605 to +2614
def _get_github_copilot_shared_api_key(
get_api_key: Callable[[], str],
model: str,
custom_llm_provider: str,
) -> str:
from litellm.llms.github_copilot.common_utils import GetAPIKeyError

try:
return get_api_key()
except GetAPIKeyError as exc:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Provider logic enters shared code

_get_github_copilot_shared_api_key adds GitHub Copilot’s error mapping to main.py. The repository requires provider-specific logic inside litellm/llms/<provider>/. Move the helper there before merging

Rule Used: What: Keep provider-specific logic inside litellm/llms/<provider>/. Shared code (main.py, utils.py, router.py, proxy/) should not branch on a provider name. Why: provider branches in shared code spread across the codebase and break silently when a p... (source)

mock_makedirs.assert_called_once()

def test_disabled_shared_login_ignores_existing_tokens(self, tmp_path):
token_dir = tmp_path / "tokens"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Tests miss required variable annotations

New test locals such as token_dir lack Final annotations. AGENTS.md requires every variable to use Final. Apply that requirement throughout the added Python tests before merging

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@codecov

codecov Bot commented Oct 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 31 untouched benchmarks


Comparing litellm_github_copilot_proxy_per_user_only (6c1d851) with main (141dba2)

Open in CodSpeed

This branch is waiting to be deployed

1 waiting deployment
e2e-changed — 6c1d851e Waiting Oct 10, 2026 by devin-ai-integration[bot] via oauth #4246
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants