Skip to content

fix(copilot): use GitHub App token flow for session token exchange#19350

Closed
ben-vargas wants to merge 1 commit intoanomalyco:devfrom
ben-vargas:fix-copilot-token-exchange
Closed

fix(copilot): use GitHub App token flow for session token exchange#19350
ben-vargas wants to merge 1 commit intoanomalyco:devfrom
ben-vargas:fix-copilot-token-exchange

Conversation

@ben-vargas
Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #19338

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Preview models (like claude-opus-4.6-fast) fail with model_not_supported because the copilot plugin sends the raw OAuth token straight to the API. Three things required changing:

  1. Device flow used an OAuth App (Ov23) which produces gho_ tokens... the token exchange endpoint rejects those. Switched to the Copilot CLI GitHub App (Iv1.b507a08c87ecfe98) which produces ghu_ tokens that can actually be exchanged.
  2. No session token exchange — added GET /copilot_internal/v2/token to get a proper tid=... session token. Cached in auth store, refreshes 5 min before expiry.
  3. Missing Editor-Version/Copilot-Integration-Id headers on API requests; session tokens are scoped to an integration and the API 403s without them.

Also handled refresh_token/expires_in from the device flow in case the app enables token expiration. The refresh/exchange path is serialized with Lock.write() following exiting project patterns to prevent concurrent requests from racing on single-use refresh tokens, and rotated refresh tokens are persisted immediately to avoid loss on subsequent failures. Legacy gho_ users skip the exchange entirely and fall back to direct token use (GA models keep working).

Of course, this may be purposefully configured today in agreement with Microsoft/GitHub, if this goes beyond "what is allowed" then feel free to close this PR and related Issue. However, if this is accepted or maintainers make similar code changes based on this PR, opencode users can then use preview models with their GitHub Copilot sub.

How did you verify your code works?

Tested each failure mode with curl against the Copilot API (details in #19338). Built locally, re-authed, confirmed claude-opus-4.6-fast now works. All 1529 unit tests pass.

Screenshots / recordings

N/A — no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Two issues prevented preview models (e.g. claude-opus-4.6-fast) from
working through GitHub Copilot:

1. The OAuth device flow used an OAuth App client ID (Ov23li8tweQw6odWQebz)
   which produces gho_ tokens. The Copilot session token exchange endpoint
   (/copilot_internal/v2/token) only accepts GitHub App user tokens (ghu_).
   Switch to the Copilot CLI GitHub App (Iv1.b507a08c87ecfe98) which
   produces ghu_ tokens that can be exchanged.

2. The raw OAuth token was sent directly as the Bearer token in API
   requests. Preview models require a proper Copilot session token
   (tid=...) obtained via the token exchange endpoint.

Add a token exchange step in the fetch wrapper that calls
/copilot_internal/v2/token to obtain a short-lived session token.
The session token is cached in the auth store and refreshed 5 minutes
before expiry. Legacy gho_ tokens gracefully fall back to direct use
(GA models continue to work, preview models will show a clear API error).

Note: existing users with gho_ tokens will need to re-authenticate
via the device flow to get a ghu_ token for full preview model support.

Fixes anomalyco#19338
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Found potential related PRs:

  1. PR fix(copilot): add token exchange and editor headers for corporate network compatibility #18782 - fix(copilot): add token exchange and editor headers for corporate network compatibility

    • This appears to address similar issues with token exchange and editor headers needed for API requests
  2. PR fix(opencode): exchange OAuth token for Copilot JWT to fix GitHub Enterprise auth #14189 - fix(opencode): exchange OAuth token for Copilot JWT to fix GitHub Enterprise auth

    • This addresses token exchange functionality, though potentially for a different use case (GitHub Enterprise)

These PRs may be related to the same token exchange/session token functionality. You should review them to confirm whether they're addressing the same root cause or if they're separate fixes that complement each other.

// Add a small safety buffer when polling to avoid hitting the server
// slightly too early due to clock skew / timer drift.
const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000 // 3 seconds
const CLIENT_ID = "Iv1.b507a08c87ecfe98"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No u cannot do this, this would violate the terms of our partnership with github copilot. We must use our id, not theirs.

@ben-vargas
Copy link
Copy Markdown
Contributor Author

@rekram1-node - I guess the question would be... has Anomoly registered as a GitHub App (which I believe produces ghu_ tokens that the exchange endpoint might accept for token exchange), or does it want to work with GitHub to get the existing OAuth App tokens whitelisted for the exchange endpoint?

Probably the broader question... does GitHub intentionally lock the "preview" models to their CLI and SDK only, or will they allow opencode users to be able to use their sub with preview models?

If not possible for Anomoly, or GitHub doesn't want opencode users to hit "preview" models, then I think this PR and the related issue can be closed. I'm just not sure if this is a purposeful block or incidental implementation byproduct.

@ben-vargas
Copy link
Copy Markdown
Contributor Author

And of course, if there's an Anomaly Client ID that does allow token exchange, absolutely happy to swap that in! I just couldn't get a token exchange to work with Anomaly's ID, and just not sure if that is a GitHub App vs OAuth registration issue, GitHub purposeful block, or what.

But, feel free the close if most appropriate path.

@ben-vargas
Copy link
Copy Markdown
Contributor Author

Also, just saw #12258 (comment) which may confirm this is intentional and not allowed/possible in which case this PR can be closed.

@ben-vargas
Copy link
Copy Markdown
Contributor Author

Per discussion in #19338

  1. Wrong OAuth App for device flow

Incorrect, we have our own oauth app and we are required to use it.

If that's the only one Anomaly has, it does not work for exchanging ghu_ tokens, so what this PR is trying to achieve doesn't sound possible with the Anomaly Client ID and this can probably be closed.

@ben-vargas ben-vargas closed this Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GitHub Copilot preview models rejected — auth plugin sends raw OAuth token instead of exchanging for Copilot session token

2 participants