Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 17, 2026

Summary

Implements interactive OAuth 2.1 with PKCE for stdio mode, allowing browser-based authentication without manual PAT creation. Falls back to PAT if OAuth not configured.

Why

stdio users currently must manually create and manage Personal Access Tokens. OAuth provides a better UX with interactive browser consent while maintaining security through PKCE (no client secret required for public clients).

What changed

  • New internal/oauth package implementing OAuth 2.1 with PKCE S256
    • Local callback server on random port
    • Automatic browser launch with fallback to manual URL
    • 5-minute configurable timeout with context cancellation
  • CLI flags: --oauth-client-id, --oauth-client-secret, --oauth-scopes
  • OAuth endpoints adapt to --gh-host for GHES/GHEC support
  • Default scopes: repo, user, gist, notifications, read:org, project

MCP impact

  • No tool or API changes

Security / limits

  • Auth / permissions considered
    • Uses golang.org/x/oauth2 (no custom auth code)
    • PKCE S256 prevents code interception
    • State parameter prevents CSRF
    • ReadHeaderTimeout prevents Slowloris
    • Tokens never persisted to disk

Tool renaming

  • I am not renaming tools as part of this PR

Lint & tests

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

Docs

  • Updated (README / docs / examples)
    • New "OAuth Authentication (stdio mode)" section
    • Setup instructions for GitHub OAuth apps
    • Usage examples for github.com, GHES, custom scopes

Usage:

# Browser opens automatically, user approves scopes
export GITHUB_OAUTH_CLIENT_ID=Iv1.abc123
./github-mcp-server stdio

# Custom scopes
./github-mcp-server stdio --oauth-client-id YOUR_ID --oauth-scopes repo,user

# GHES
./github-mcp-server stdio --oauth-client-id YOUR_ID --gh-host https://github.enterprise.com

Flow:

  1. User starts with --oauth-client-id (no PAT)
  2. Server generates PKCE verifier/challenge
  3. Browser opens to GitHub authorization
  4. User approves → GitHub redirects to localhost
  5. Server exchanges code+verifier for token
  6. Server starts with OAuth token

stdio-only by design. Remote server continues using PATs.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • go.googlesource.com
    • Triggering command: /update-job-proxy /update-job-proxy --64 -o ux_amd64/link -o 4065655/b332/_pkg_.a -trimpath stdio -p b/github-mcp-serrev-parse -lang=go1.16 /opt/hostedtoolcache/go/1.24.11/x64/pkg/tool/linux_amd64/vet -uns�� zp0b/qdh15NexuYWXrf2mzp0b /tmp/go-build2265561799/b136/vet.cfg x64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg x64/pkg/tool/linux_amd64/vet (dns block)
    • Triggering command: /update-job-proxy /update-job-proxy -o br-1cd4237c9914 -j DROP e/vcs/eb6bc1bfa080591d5c70f29cb5--detach sed ub.com/.insteadOf 2_G3.pem /usr/share/ca-ce--shallow-file k 7d017ee21785da21rev-list -e e=false sed e/git-remote-htt--alternate-refs fflib %H %ct %D 798c1aaeb27a4ebc-t e/git-remote-httfilter (dns block)
  • go.yaml.in
    • Triggering command: /update-job-proxy /update-job-proxy --64 -o ux_amd64/link -o 4065655/b332/_pkg_.a -trimpath stdio -p b/github-mcp-serrev-parse -lang=go1.16 /opt/hostedtoolcache/go/1.24.11/x64/pkg/tool/linux_amd64/vet -uns�� zp0b/qdh15NexuYWXrf2mzp0b /tmp/go-build2265561799/b136/vet.cfg x64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg x64/pkg/tool/linux_amd64/vet (dns block)
    • Triggering command: /update-job-proxy /update-job-proxy -o br-1cd4237c9914 -j DROP e/vcs/eb6bc1bfa080591d5c70f29cb5--detach sed ub.com/.insteadOf 2_G3.pem /usr/share/ca-ce--shallow-file k 7d017ee21785da21rev-list -e e=false sed e/git-remote-htt--alternate-refs fflib %H %ct %D 798c1aaeb27a4ebc-t e/git-remote-httfilter (dns block)
  • gopkg.in
    • Triggering command: /update-job-proxy /update-job-proxy --64 -o ux_amd64/link -o 4065655/b332/_pkg_.a -trimpath stdio -p b/github-mcp-serrev-parse -lang=go1.16 /opt/hostedtoolcache/go/1.24.11/x64/pkg/tool/linux_amd64/vet -uns�� zp0b/qdh15NexuYWXrf2mzp0b /tmp/go-build2265561799/b136/vet.cfg x64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg x64/pkg/tool/linux_amd64/vet (dns block)
    • Triggering command: /update-job-proxy /update-job-proxy -o br-1cd4237c9914 -j DROP e/vcs/eb6bc1bfa080591d5c70f29cb5--detach sed ub.com/.insteadOf 2_G3.pem /usr/share/ca-ce--shallow-file k 7d017ee21785da21rev-list -e e=false sed e/git-remote-htt--alternate-refs fflib %H %ct %D 798c1aaeb27a4ebc-t e/git-remote-httfilter (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Is there a way you could implement a standard oauth flow on initialize or in a pre-request middleware or something in the stdio startup rather than device flow like in #1649 where we use a standard golang library that can provide interactive oauth, and complete the oauth flow as a standard rather than device flow, still taking an optional app, but without all the complexity, just the user starts the server, and if no token is present it does an interactive oauth flow and then logs in. If it cannot be seamlessly added into the package, we could emulatte 1649 that might have to be it. Maybe it can be any tool call, where it kicks off the oauth flow.

We only want this to be in STDIO mode, as this repo is used as a library for a remote server.

If it helps we can also use our own protected resource metadata and URL https://api.githubcopilot.com/.well-known/oauth-protected-resource/mcp which is for https://api.githubcopilot.com/mcp

I don't know that that helps, but it's the same concept and same owner and authorization details are there.

If there is prior art and you can think a good way to get the auth challenge to the user, I think we might still need secure URL elicitation, as we cannot do it interactively otherwise while ensuring the user sees the link.

Anyway, make it a relatively small change, try to keep code to an auth specific module, and hook into the server as cleanly as possible. This is the work of an expert staff and auth engineer who knows above all else, you don't roll your own auth code, you lean into the existing tested and autited implementations. Our authorization also suppors PKCE so you should be able to do oauth 2.1 other than requiring an app so Dynamic Client Registration is not possible.

Do a good, safe job so stdio users can have access to GitHub MCP.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 5 commits January 17, 2026 23:47
- Create internal/oauth package with standard OAuth implementation
- Use golang.org/x/oauth2 for PKCE flow with S256 challenge
- Support interactive browser-based authorization
- Add CLI flags: --oauth-client-id, --oauth-client-secret, --oauth-scopes
- Respect --gh-host for GHES/GHEC OAuth endpoints
- Secure implementation with ReadHeaderTimeout, state validation
- Comprehensive tests and linting passing

Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com>
- Document OAuth 2.1 PKCE flow for stdio mode
- Include setup instructions for GitHub OAuth apps
- Document environment variables and CLI flags
- Add usage examples with custom scopes
- Note that OAuth is stdio-only (not for remote server)

Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com>
- Add DefaultAuthTimeout constant for configurability
- Fix string index check to handle idx >= 0 correctly
- Use cmd.Context() for proper cancellation support
- Add named constant for PKCE verifier length in test
- Remove unused context import

Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com>
- Clarify string index boundary check logic (idx > 0 is correct)
- Update error message to show both flag and env var options
- Add comment explaining the boundary check reasoning

Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com>
- Linting: ✅ 0 issues
- Tests: ✅ All passing
- CodeQL: ✅ 0 security alerts
- Build: ✅ Binary builds successfully

Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com>
Copilot AI changed the title [WIP] Add standard OAuth flow in STDIO mode Add OAuth 2.1 PKCE authentication for stdio mode Jan 17, 2026
Copilot AI requested a review from SamMorrowDrums January 17, 2026 23:56
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