Skip to content

Commit 8ce77e3

Browse files
feat(oauth): add stdio OAuth 2.1 login core library (1/4) (#2704)
* feat(oauth): add stdio OAuth 2.1 stdio login Introduce internal/oauth, a self-contained library that performs the user-facing GitHub OAuth login the stdio server uses to obtain a token without a pre-provisioned PAT. It is independent of MCP: client concerns (elicitation) sit behind the Prompter interface so the flows are testable without a live session. What it provides: - Authorization-code + PKCE flow with a local loopback callback server, state/CSRF validation, and XSS-safe result pages. - Device-authorization flow as a fallback (headless, containers). - A Manager that selects the most secure available channel (browser auto-open -> URL elicitation -> last-resort user action), runs a single flow at a time, and exposes a refreshing token source. Both GitHub OAuth Apps and GitHub Apps are supported without special casing: the token is modeled as an x/oauth2 refreshing TokenSource, so expiring GitHub App user tokens are renewed transparently (the gap that made a stored-token approach silently die after ~8h). When a client lacks secure URL elicitation and the flow falls back to a tool-response message, the message advises the user that their agent/CLI/ IDE does not appear to support URL elicitation and suggests requesting it for improved security. Tests exercise real protocol behavior against an httptest GitHub stand-in: PKCE challenge/verifier, GitHub App refresh-on-expiry, device polling, URL elicitation, declined prompts, the last-resort action with advisory, and single-flight concurrency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(oauth): reap browser launcher and keep native callback on loopback Address code review: - openBrowser: reap the launcher process asynchronously so it does not linger as a zombie for the lifetime of the server. - listenCallback: take an explicit bindAll flag and bind to all interfaces only inside a container (where the published port arrives via eth0). A native run, even with a fixed callback port, now stays on 127.0.0.1 instead of 0.0.0.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(oauth): fail fast when a fixed callback port is unavailable A fixed --oauth-callback-port is registered with the OAuth app and chosen deliberately, so a bind failure means another process holds the port and could intercept the authorization redirect. Treat that as fatal instead of silently downgrading to the device flow, which would mask the conflict. Also warn, when binding the callback inside a container, that the listener is on all interfaces and should be published to loopback only so the authorization code is not exposed on the container network. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(oauth): surface refresh failures, bound refresh, prefer device flow when headless Addresses pre-merge review of the OAuth stdio core: - Log a one-time warning when token refresh fails instead of silently returning an empty access token, so a forced re-login isn't a surprise. - Bound each background token refresh with a 30s HTTP client timeout so a stalled GitHub token endpoint can't block tool calls indefinitely. - On a headless host (no display server) with a random callback port, fall back to the device-code flow — the only channel reachable from a browser on another machine — instead of dead-ending on an unreachable localhost redirect. A generic browser-open failure still offers the manual URL. - Mark the callback bind failure with a sentinel so the fixed-port-busy fatal path can't misreport an unrelated error as a port conflict. - Export NormalizeHost so callers can recognize the default github.com host (consumed by the build-time baked-in credential guard). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(oauth): wire stdio OAuth 2.1 login into the server (2/4) (#2710) * feat(oauth): wire stdio OAuth 2.1 login into the server Connect the internal/oauth core library to the stdio MCP server so users can authenticate with an OAuth App or GitHub App client ID instead of a static personal access token. - BearerAuthTransport gains a TokenProvider that is consulted per request, letting the lazily-acquired, auto-refreshing OAuth token take effect without rebuilding the client. - createGitHubClients uses BearerAuthTransport (and skips go-github's WithAuthToken, which would pin a static token) when a TokenProvider is set. - RunStdioServer starts without a token and installs receiving middleware that runs the authorization flow on the first tool call, surfacing the auth URL or device code via elicitation (or a tool result as a fallback). - Tool filtering uses the requested OAuth scopes; the default supported set hides nothing, while a narrower --oauth-scopes both narrows the grant and filters tools accordingly. - A sessionPrompter adapts the MCP server session to oauth.Prompter, keeping the authorization URL off the model's context. - New stdio flags: --oauth-client-id/-client-secret/-scopes/-callback-port. This is stdio-only and deliberately does not touch MCP-HTTP auth. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(oauth): address review — omit empty bearer header, guard token/oauth - BearerAuthTransport omits the Authorization header entirely when the token is empty (pre-authorization) rather than sending an empty "Bearer " value. - RunStdioServer rejects the ambiguous combination of a static Token and an OAuthManager up front, enforcing the documented mutual exclusivity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(oauth): clarify SupportedScopes is the stdio default and tool filter Document that stdio OAuth login requests these scopes by default and then filters the exposed tools to the scopes actually granted, so a tool whose required scope is absent from this list is hidden under default OAuth even though a PAT carrying that scope would expose it. Keep the list in sync with tool scope requirements when scopes change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Distinguish undeliverable auth prompts from user declines An elicitation prompt that the client cannot deliver (a transport or protocol failure) was treated the same as a user actively declining: any display error cancelled the flow. That conflated a system failure with a deliberate "no", so a client that advertised URL elicitation but failed to deliver it would hard-fail the login instead of degrading. Add an ErrPromptUnavailable sentinel alongside ErrPromptDeclined and have the MCP adapter return it when Elicit fails at the transport level. The manager now falls back to the manual user-action channel on an undeliverable prompt (keeping the background flow alive so the user can still authorize out of band), while a genuine decline still aborts. A context-cancelled prompt is checked first so an ending flow is never misread as a transport failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * build(oauth): bake in default OAuth credentials for official releases (3/4) (#2711) * build(oauth): bake in default OAuth credentials via build-time ldflags Inject the public OAuth client credentials (stored as the OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET repo secrets) at build time via -ldflags so official binaries and images ship a working default app for zero-config login. Security relies on PKCE, not on the secret. Local/dev builds leave the values empty and continue to require an explicit token or --oauth-client-id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(oauth): recognize github.com host aliases for the baked-in client Match the default host via oauth.NormalizeHost instead of only an empty host string, so an explicit GITHUB_HOST=github.com (or api.github.com) still counts as the default and keeps zero-config baked-in login working. GHES and ghe.com users continue to bring their own --oauth-client-id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(oauth): document stdio OAuth login; make PAT optional in install config (#2717) Add a dedicated Local Server OAuth Login guide (docs/oauth-login.md) covering the PKCE/device flows, display channels and the URL-elicitation security advisory, scope-based tool filtering, the fixed-port Docker recipe and its loopback/port-safety behavior, bringing your own OAuth or GitHub App, and the GitHub Enterprise Server / ghe.com requirement to register an app on that host (custom --gh-host directs login at that instance's authorization server). Reflect that the local server now logs in with OAuth by default on github.com: - README: make the stdio Docker install badges OAuth-first (fixed callback port 8085 published to loopback), drop the PAT prompt, and reframe the PAT as an optional alternative with a pointer to the new guide. - server.json: make GITHUB_PERSONAL_ACCESS_TOKEN optional and publish the OAuth callback port so the registry default works without a token. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 63d313a commit 8ce77e3

29 files changed

Lines changed: 2883 additions & 25 deletions

.github/workflows/docker-publish.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ jobs:
117117
platforms: linux/amd64,linux/arm64
118118
build-args: |
119119
VERSION=${{ github.ref_name }}
120+
secrets: |
121+
oauth_client_id=${{ secrets.OAUTH_CLIENT_ID }}
122+
oauth_client_secret=${{ secrets.OAUTH_CLIENT_SECRET }}
120123
121124
# Sign the resulting Docker image digest except on PRs.
122125
# This will only write to the public Rekor transparency log when the Docker

.github/workflows/goreleaser.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
workdir: .
3939
env:
4040
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41+
OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
42+
OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
4143

4244
- name: Generate signed build provenance attestations for workflow artifacts
4345
uses: actions/attest-build-provenance@v4

.goreleaser.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ builds:
99
- env:
1010
- CGO_ENABLED=0
1111
ldflags:
12-
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
12+
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientID={{ .Env.OAUTH_CLIENT_ID }} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientSecret={{ .Env.OAUTH_CLIENT_SECRET }}
1313
goos:
1414
- linux
1515
- windows

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ COPY . .
2424
COPY --from=ui-build /app/pkg/github/ui_dist/* ./pkg/github/ui_dist/
2525

2626
# Build the server
27+
# OAuth credentials are injected via build secrets so they are not baked into image history; the values are public in practice but kept out of layers.
2728
RUN --mount=type=cache,target=/go/pkg/mod \
2829
--mount=type=cache,target=/root/.cache/go-build \
29-
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
30+
--mount=type=secret,id=oauth_client_id \
31+
--mount=type=secret,id=oauth_client_secret \
32+
export OAUTH_CLIENT_ID="$(cat /run/secrets/oauth_client_id 2>/dev/null || echo '')" && \
33+
export OAUTH_CLIENT_SECRET="$(cat /run/secrets/oauth_client_secret 2>/dev/null || echo '')" && \
34+
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ) -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientID=${OAUTH_CLIENT_ID} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientSecret=${OAUTH_CLIENT_SECRET}" \
3035
-o /bin/github-mcp-server ./cmd/github-mcp-server
3136

3237
# Make a stage to run the app

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,15 @@ GitHub Enterprise Server does not support remote server hosting. Please refer to
176176

177177
## Local GitHub MCP Server
178178

179-
[![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=github&inputs=%5B%7B%22id%22%3A%22github_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22GitHub%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-e%22%2C%22GITHUB_PERSONAL_ACCESS_TOKEN%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%2C%22env%22%3A%7B%22GITHUB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agithub_token%7D%22%7D%7D) [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=github&inputs=%5B%7B%22id%22%3A%22github_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22GitHub%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-e%22%2C%22GITHUB_PERSONAL_ACCESS_TOKEN%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%2C%22env%22%3A%7B%22GITHUB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agithub_token%7D%22%7D%7D&quality=insiders) [![Install with Docker in Visual Studio](https://img.shields.io/badge/Visual_Studio-Install_Server-C16FDE?style=flat-square&logo=visualstudio&logoColor=white)](https://aka.ms/vs/mcp-install?%7B%22name%22%3A%22github%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-e%22%2C%22GITHUB_PERSONAL_ACCESS_TOKEN%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%7D)
179+
[![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-p%22%2C%22127.0.0.1%3A8085%3A8085%22%2C%22-e%22%2C%22GITHUB_OAUTH_CALLBACK_PORT%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%2C%22env%22%3A%7B%22GITHUB_OAUTH_CALLBACK_PORT%22%3A%228085%22%7D%7D) [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-p%22%2C%22127.0.0.1%3A8085%3A8085%22%2C%22-e%22%2C%22GITHUB_OAUTH_CALLBACK_PORT%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%2C%22env%22%3A%7B%22GITHUB_OAUTH_CALLBACK_PORT%22%3A%228085%22%7D%7D&quality=insiders) [![Install with Docker in Visual Studio](https://img.shields.io/badge/Visual_Studio-Install_Server-C16FDE?style=flat-square&logo=visualstudio&logoColor=white)](https://aka.ms/vs/mcp-install?%7B%22name%22%3A%22github%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22-i%22%2C%22--rm%22%2C%22-p%22%2C%22127.0.0.1%3A8085%3A8085%22%2C%22-e%22%2C%22GITHUB_OAUTH_CALLBACK_PORT%3D8085%22%2C%22ghcr.io%2Fgithub%2Fgithub-mcp-server%22%5D%7D)
180180

181181
### Prerequisites
182182

183183
1. To run the server in a container, you will need to have [Docker](https://www.docker.com/) installed.
184184
2. Once Docker is installed, you will also need to ensure Docker is running. The Docker image is available at `ghcr.io/github/github-mcp-server`. The image is public; if you get errors on pull, you may have an expired token and need to `docker logout ghcr.io`.
185-
3. Lastly you will need to [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new).
186-
The MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)).
185+
3. **Authentication.** On github.com you don't need to create anything up front — the one-click buttons above log you in with OAuth on first use (a browser-based flow; the token is kept in memory only). The Docker buttons publish a fixed callback port (`127.0.0.1:8085`) so the container's login callback is reachable. See **[Local Server OAuth Login](docs/oauth-login.md)** for how it works, headless/device-code fallback, and bringing your own OAuth or GitHub App (required for GitHub Enterprise Server and `ghe.com`).
186+
187+
Prefer a token? You can still authenticate with a [GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new) by setting `GITHUB_PERSONAL_ACCESS_TOKEN` instead (it takes precedence over OAuth). The MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)).
187188

188189
<details><summary><b>Handling PATs Securely</b></summary>
189190

@@ -281,6 +282,8 @@ Install in GitHub Copilot on other IDEs (JetBrains, Visual Studio, Eclipse, etc.
281282

282283
Add the following JSON block to your IDE's MCP settings.
283284

285+
> The examples below authenticate with a Personal Access Token. To log in with OAuth instead (no token to create or store), see **[Local Server OAuth Login](docs/oauth-login.md)** — in Docker it needs a fixed callback port, as the one-click buttons above show.
286+
284287
```json
285288
{
286289
"mcp": {

cmd/github-mcp-server/main.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import (
77
"strings"
88
"time"
99

10+
"github.com/github/github-mcp-server/internal/buildinfo"
1011
"github.com/github/github-mcp-server/internal/ghmcp"
12+
"github.com/github/github-mcp-server/internal/oauth"
1113
"github.com/github/github-mcp-server/pkg/github"
1214
ghhttp "github.com/github/github-mcp-server/pkg/http"
15+
ghoauth "github.com/github/github-mcp-server/pkg/http/oauth"
1316
"github.com/spf13/cobra"
1417
"github.com/spf13/pflag"
1518
"github.com/spf13/viper"
@@ -34,8 +37,21 @@ var (
3437
Long: `Start a server that communicates via standard input/output streams using JSON-RPC messages.`,
3538
RunE: func(_ *cobra.Command, _ []string) error {
3639
token := viper.GetString("personal_access_token")
37-
if token == "" {
38-
return errors.New("GITHUB_PERSONAL_ACCESS_TOKEN not set")
40+
oauthClientID := viper.GetString("oauth-client-id")
41+
oauthClientSecret := viper.GetString("oauth-client-secret")
42+
// Fall back to the build-time baked-in client (official releases) when none is
43+
// configured explicitly. The baked-in app is registered on github.com, so it is
44+
// only applied to the default host; GHES/ghe.com users must bring their own
45+
// --oauth-client-id. Recognizing the host via NormalizeHost means an explicit
46+
// GITHUB_HOST=github.com (or api.github.com) still counts as the default and keeps
47+
// zero-config login working. The secret tracks the id, so an explicitly provided
48+
// id with no secret never picks up the baked-in secret.
49+
if oauthClientID == "" && oauth.NormalizeHost(viper.GetString("host")) == "https://github.com" {
50+
oauthClientID = buildinfo.OAuthClientID
51+
oauthClientSecret = buildinfo.OAuthClientSecret
52+
}
53+
if token == "" && oauthClientID == "" {
54+
return errors.New("authentication required: set GITHUB_PERSONAL_ACCESS_TOKEN, or pass --oauth-client-id to log in via OAuth")
3955
}
4056

4157
// If you're wondering why we're not using viper.GetStringSlice("toolsets"),
@@ -95,6 +111,29 @@ var (
95111
ExcludeTools: excludeTools,
96112
RepoAccessCacheTTL: &ttl,
97113
}
114+
115+
// When no static token is provided, log in via OAuth using the given
116+
// client. The requested scopes default to the full supported set
117+
// (which filters out no tools); an explicit, narrower --oauth-scopes
118+
// both narrows the grant and hides tools needing other scopes.
119+
if token == "" {
120+
scopes := ghoauth.SupportedScopes
121+
if viper.IsSet("oauth-scopes") {
122+
if err := viper.UnmarshalKey("oauth-scopes", &scopes); err != nil {
123+
return fmt.Errorf("failed to unmarshal oauth-scopes: %w", err)
124+
}
125+
}
126+
oauthConfig := oauth.NewGitHubConfig(
127+
oauthClientID,
128+
oauthClientSecret,
129+
scopes,
130+
viper.GetString("host"),
131+
viper.GetInt("oauth-callback-port"),
132+
)
133+
stdioServerConfig.OAuthManager = oauth.NewManager(oauthConfig, nil)
134+
stdioServerConfig.OAuthScopes = scopes
135+
}
136+
98137
return ghmcp.RunStdioServer(stdioServerConfig)
99138
},
100139
}
@@ -183,6 +222,14 @@ func init() {
183222
rootCmd.PersistentFlags().Bool("insiders", false, "Enable insiders features")
184223
rootCmd.PersistentFlags().Duration("repo-access-cache-ttl", 5*time.Minute, "Override the repo access cache TTL (e.g. 1m, 0s to disable)")
185224

225+
// stdio-specific OAuth flags. Provide --oauth-client-id (instead of a token)
226+
// to log in via the browser-based OAuth flow on first use. Works for both
227+
// OAuth Apps and GitHub Apps.
228+
stdioCmd.Flags().String("oauth-client-id", "", "OAuth App or GitHub App client ID, enabling interactive OAuth login when no token is set")
229+
stdioCmd.Flags().String("oauth-client-secret", "", "OAuth client secret, if the app requires one (it is a public, non-confidential credential for distributed clients)")
230+
stdioCmd.Flags().StringSlice("oauth-scopes", nil, "Comma-separated OAuth scopes to request; also filters tools to those scopes. Defaults to the full supported set")
231+
stdioCmd.Flags().Int("oauth-callback-port", 0, "Fixed local port for the OAuth callback server. Defaults to a random port; set a fixed port when mapping it through Docker")
232+
186233
// HTTP-specific flags
187234
httpCmd.Flags().Int("port", 8082, "HTTP server port")
188235
httpCmd.Flags().String("listen-host", "", "Host the HTTP server binds to (e.g. 127.0.0.1). Empty binds to all interfaces.")
@@ -205,6 +252,10 @@ func init() {
205252
_ = viper.BindPFlag("lockdown-mode", rootCmd.PersistentFlags().Lookup("lockdown-mode"))
206253
_ = viper.BindPFlag("insiders", rootCmd.PersistentFlags().Lookup("insiders"))
207254
_ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl"))
255+
_ = viper.BindPFlag("oauth-client-id", stdioCmd.Flags().Lookup("oauth-client-id"))
256+
_ = viper.BindPFlag("oauth-client-secret", stdioCmd.Flags().Lookup("oauth-client-secret"))
257+
_ = viper.BindPFlag("oauth-scopes", stdioCmd.Flags().Lookup("oauth-scopes"))
258+
_ = viper.BindPFlag("oauth-callback-port", stdioCmd.Flags().Lookup("oauth-callback-port"))
208259
_ = viper.BindPFlag("port", httpCmd.Flags().Lookup("port"))
209260
_ = viper.BindPFlag("listen-host", httpCmd.Flags().Lookup("listen-host"))
210261
_ = viper.BindPFlag("base-url", httpCmd.Flags().Lookup("base-url"))

0 commit comments

Comments
 (0)