opencode
opencode copied to clipboard
fix: use localhost instead of 127.0.0.1 for OAuth callback
This fixes the OAuth flow in WSL2 where 127.0.0.1 inside WSL is not accessible from the Windows host browser. Using localhost enables WSL2's built-in localhost forwarding between Windows and WSL.
🤖 Generated with Claude Code
aside i dont know if localhost causes issues in some scenarios?
will run the generate command and update pr
Likely a path here where I could just detect WSL but it might not be worth it. I think the "theres no dns/localhost" case is probably an outlier. Willing to be convinced, but I'm not sure the complexity of OS detection is worth it if its a 0.001% kind of thing.
example:
diff --git a/packages/opencode/src/mcp/oauth-callback.ts b/packages/opencode/src/mcp/oauth-callback.ts
index c434b21ed..218aa5fec 100644
--- a/packages/opencode/src/mcp/oauth-callback.ts
+++ b/packages/opencode/src/mcp/oauth-callback.ts
@@ -1,5 +1,5 @@
import { Log } from "../util/log"
-import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider"
+import { OAUTH_CALLBACK_HOST, OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider"
const log = Log.create({ service: "mcp.oauth-callback" })
@@ -161,7 +161,7 @@ export namespace McpOAuthCallback {
export async function isPortInUse(): Promise<boolean> {
return new Promise((resolve) => {
Bun.connect({
- hostname: "localhost",
+ hostname: OAUTH_CALLBACK_HOST,
port: OAUTH_CALLBACK_PORT,
socket: {
open(socket) {
diff --git a/packages/opencode/src/mcp/oauth-provider.ts b/packages/opencode/src/mcp/oauth-provider.ts
index 3661034cc..9324da977 100644
--- a/packages/opencode/src/mcp/oauth-provider.ts
+++ b/packages/opencode/src/mcp/oauth-provider.ts
@@ -7,9 +7,21 @@ import type {
} from "@modelcontextprotocol/sdk/shared/auth.js"
import { McpAuth } from "./auth"
import { Log } from "../util/log"
+import { release } from "os"
const log = Log.create({ service: "mcp.oauth" })
+function getLoopbackHost(): string {
+ // WSL requires localhost for Windows host browser -> WSL callback forwarding
+ // Pattern matches clipboard.ts:32
+ if (release().includes("WSL")) {
+ return "localhost"
+ }
+ // 127.0.0.1 is guaranteed to work without DNS resolution
+ return "127.0.0.1"
+}
+
+const OAUTH_CALLBACK_HOST = getLoopbackHost()
const OAUTH_CALLBACK_PORT = 19876
const OAUTH_CALLBACK_PATH = "/mcp/oauth/callback"
@@ -32,7 +44,7 @@ export class McpOAuthProvider implements OAuthClientProvider {
) {}
get redirectUrl(): string {
- return `http://localhost:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}`
+ return `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}`
}
get clientMetadata(): OAuthClientMetadata {
@@ -151,4 +163,4 @@ export class McpOAuthProvider implements OAuthClientProvider {
}
}
-export { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH }
+export { OAUTH_CALLBACK_HOST, OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH }