You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The GitHub MCP Server supports OAuth 2.1 authentication for stdio mode, allowing users to authenticate via their browser instead of manually creating Personal Access Tokens.
4
+
5
+
## How It Works
6
+
7
+
When no `GITHUB_PERSONAL_ACCESS_TOKEN` is configured and OAuth credentials are available, the server starts without a token. On the first tool call, it triggers the OAuth flow:
8
+
9
+
1.**PKCE flow** (primary): A local callback server starts, your browser opens to GitHub's authorization page, and the token is received via callback. If the browser cannot open (e.g., Docker), the authorization URL is shown via [MCP URL elicitation](https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation).
10
+
11
+
2.**Device flow** (fallback): If the callback server cannot start (e.g., Docker without port binding), the server falls back to GitHub's [device flow](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow). A code is displayed that you enter at [github.com/login/device](https://github.com/login/device).
12
+
13
+
### Authentication Priority
14
+
15
+
| Priority | Source | Notes |
16
+
|----------|--------|-------|
17
+
| 1 (highest) |`GITHUB_PERSONAL_ACCESS_TOKEN`| PAT is used directly, OAuth is skipped |
All authorization code flows use PKCE with S256 challenge, preventing authorization code interception even if an attacker can observe the callback.
111
+
112
+
### Fixed Port Considerations
113
+
Docker requires a fixed callback port for port mapping. This is acceptable because:
114
+
-**PKCE verifier** is generated per-flow and never leaves the process — an attacker who intercepts the callback cannot exchange the code
115
+
-**State parameter** prevents CSRF — the callback validates state match
116
+
-**Callback server binds to 127.0.0.1** — not accessible from outside the host
117
+
-**Short-lived** — the server shuts down immediately after receiving the callback
118
+
119
+
### Token Handling
120
+
- Tokens are stored **in memory only** — never written to disk
121
+
- OAuth token takes precedence over PAT if both become available
122
+
- The server requests only the scopes needed by the configured tools
123
+
124
+
### URL Elicitation Security
125
+
When the browser cannot auto-open, the authorization URL is shown via MCP URL-mode elicitation. This is secure because:
126
+
- URL elicitation presents the URL to the user without exposing it to the LLM context
127
+
- The MCP client shows the full URL for user inspection before navigation
128
+
- Credentials flow directly between the user's browser and GitHub — never through the MCP channel
129
+
130
+
### Device Flow as Fallback
131
+
Device flow is more susceptible to social engineering than PKCE (the device code could theoretically be phished), which is why PKCE is always attempted first. Device flow is only used when a callback server cannot be started.
0 commit comments