Skip to content

Token scopes context#1997

Open
omgitsads wants to merge 9 commits intomainfrom
token-scopes-context
Open

Token scopes context#1997
omgitsads wants to merge 9 commits intomainfrom
token-scopes-context

Conversation

@omgitsads
Copy link
Member

@omgitsads omgitsads commented Feb 11, 2026

Summary

So that I can setup the scopes of a token before it is authed, separate the TokenScopes from the TokenInfo contexts. In the remote MCP server, by the time ExtractUserToken happens, we already know that

Why

Gives us greater flexibility for handling authentication in a gateway and pre-populating token scopes.

What changed

  • Store scopes in a Seperate context window.

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added

Prompts tested (tool changes only)

Security / limits

  • No security or limits impact
  • Auth / permissions considered
  • Data exposure, filtering, or token/size limits considered

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Note: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Not needed
  • Updated (README / docs / examples)

This allows us to provide scopes seperately in the remote server, where
we have scopes before we do the auth.
This is to avoid redundant token extraction in remote setup where token info may have already been extracted earlier in the request lifecycle.
Copilot AI review requested due to automatic review settings February 11, 2026 14:30
@omgitsads omgitsads requested a review from a team as a code owner February 11, 2026 14:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR separates OAuth/PAT scope storage from TokenInfo by introducing a dedicated “token scopes” context value, enabling upstream/remote deployments to pre-populate scopes and avoid redundant GitHub API calls.

Changes:

  • Add WithTokenScopes / GetTokenScopes context helpers and remove scope fields from TokenInfo.
  • Update HTTP middleware and inventory filtering to read/write scopes via the new context value.
  • Update PAT scope middleware tests to assert scopes are stored in context.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pkg/http/middleware/token.go Skip token extraction when TokenInfo is already present in request context.
pkg/http/middleware/scope_challenge.go Prefer scopes from context; fetch from GitHub only when absent; store scopes back into context.
pkg/http/middleware/pat_scope.go Prefer scopes from context; otherwise fetch and store into context.
pkg/http/middleware/pat_scope_test.go Update tests to validate scopes are stored/retrieved via the new context helpers.
pkg/http/handler.go Update PAT tool filtering to read scopes from context (or fetch if missing).
pkg/context/token.go Remove scopes from TokenInfo; add dedicated context storage for token scopes.

Comment on lines 97 to 110
// Get OAuth scopes for Token. First check if scopes are already in context, then fetch from GitHub if not present.
// This allows Remote Server to pass scope info to avoid redundant GitHub API calls.
activeScopes, ok := ghcontext.GetTokenScopes(ctx)
if !ok {
activeScopes, err = scopeFetcher.FetchTokenScopes(ctx, tokenInfo.Token)
if err != nil {
next.ServeHTTP(w, r)
return
}
}

// Store active scopes in context for downstream use
tokenInfo.Scopes = activeScopes
tokenInfo.ScopesFetched = true
ctx = ghcontext.WithTokenInfo(ctx, tokenInfo)
ctx = ghcontext.WithTokenScopes(ctx, activeScopes)
r = r.WithContext(ctx)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

New behavior reads scopes from context to avoid redundant GitHub API calls, but there’s no unit test coverage for (1) scopes already present in context skipping FetchTokenScopes, and (2) scopes being stored back into context for downstream use. Adding a table-driven test with a mock fetcher would prevent regressions here.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +18 to +24
// Check if token info already exists in context, if it does, skip extraction.
// In remote setup, we may have already extracted token info earlier.
if _, ok := ghcontext.GetTokenInfo(ctx); ok {
// Token info already exists in context, skip extraction
next.ServeHTTP(w, r)
return
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This middleware now short-circuits when TokenInfo is already present in context, but token_test.go doesn’t cover the new branch. Add a test that pre-populates TokenInfo in the request context and asserts the middleware does not overwrite it and does not require an Authorization header.

Copilot generated this review using guidance from repository custom instructions.
// Only classic PATs (ghp_ prefix) return OAuth scopes via X-OAuth-Scopes header.
// Fine-grained PATs and other token types don't support this, so we skip filtering.
if tokenInfo.TokenType == utils.TokenTypePersonalAccessToken {
if tokenInfo.ScopesFetched {
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious, was there a reason we needed this flag at all?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was trying to handle the scenario where we had a token info from copilot API, but it was a token with no scopes. But having it combined with the TokenInfo meant the ordering was a little awkward.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's also implied now, if ok is false from scopes, ok := ghcontext.GetTokenScopes(ctx)

Copy link
Contributor

@almaleksia almaleksia left a comment

Choose a reason for hiding this comment

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

LGTM

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