Skip to content

fix(copilot): exchange raw GitHub token for Copilot API JWT#12876

Closed
difujia wants to merge 1 commit into
NousResearch:mainfrom
difujia:fix/copilot-token-exchange
Closed

fix(copilot): exchange raw GitHub token for Copilot API JWT#12876
difujia wants to merge 1 commit into
NousResearch:mainfrom
difujia:fix/copilot-token-exchange

Conversation

@difujia

@difujia difujia commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Part 2 of #7731, as scoped by @konsisumer.

Problem

Raw GitHub tokens (gho_/github_pat_/ghu_) are sent directly as Authorization: Bearer to the Copilot API. This works for basic models but does not grant access to internal-only models like claude-opus-4.6-1m (1M context), which require an exchanged Copilot API token.

Solution

Exchange raw GitHub tokens for short-lived Copilot API tokens via GET https://api.github.com/copilot_internal/v2/token before use.

Token caching strategy

Per the discussion in #7731: in-process caching only, no disk persistence.

  • Cache is a dict keyed by SHA-256 token fingerprint (first 16 hex chars)
  • Tokens are reused until 2 minutes before expires_at
  • Gateway is a long-running process, so in-memory cache is sufficient
  • Exchanged tokens are short-lived (~30 min), making disk caching high-complexity/low-value

Changes

  • hermes_cli/copilot_auth.py:
    • exchange_copilot_token(raw_token)(api_token, expires_at) — core exchange with caching
    • get_copilot_api_token(raw_token)str — convenience wrapper with graceful fallback to raw token
  • hermes_cli/auth.py: _resolve_api_key_provider_secret("copilot") now pipes through get_copilot_api_token()
  • agent/credential_pool.py: _refresh_copilot_entries() stores the exchanged token in the credential pool

Graceful fallback

If the exchange fails (network error, 401, unsupported account), get_copilot_api_token() returns the raw token unchanged. This preserves existing behavior for accounts that work without exchange.

Tests

12 new tests covering: successful exchange, caching, cache expiry, empty token response, network errors, fallback behavior, fingerprint consistency, and caller integration. All 185 existing copilot/auth/credential-pool tests pass.

Not included (separate PRs)

@alt-glitch alt-glitch added area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists provider/copilot GitHub Copilot (ACP + Chat) type/bug Something isn't working labels Apr 22, 2026
Raw GitHub tokens (gho_/github_pat_/ghu_) are now exchanged for
short-lived Copilot API tokens via /copilot_internal/v2/token before
being used as Bearer credentials. This is required to access
internal-only models (e.g. claude-opus-4.6-1m with 1M context).

Implementation:
- exchange_copilot_token(): calls the token exchange endpoint with
  in-process caching (dict keyed by SHA-256 fingerprint), refreshed
  2 minutes before expiry. No disk persistence — gateway is long-running
  so in-memory cache is sufficient.
- get_copilot_api_token(): convenience wrapper with graceful fallback —
  returns exchanged token on success, raw token on failure.
- Both callers (hermes_cli/auth.py and agent/credential_pool.py) now
  pipe the raw token through get_copilot_api_token() before use.

12 new tests covering exchange, caching, expiry, error handling,
fingerprinting, and caller integration. All 185 existing copilot/auth
tests pass.

Part 2 of NousResearch#7731.
@difujia

difujia commented Apr 24, 2026

Copy link
Copy Markdown
Contributor Author

Cherry-picked into main via d7ad07d. Thanks!

@difujia difujia closed this Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists provider/copilot GitHub Copilot (ACP + Chat) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants