Skip to content

Commit 999f815

Browse files
bywang56laileni-aws
authored andcommitted
fix: fix pkce windows url path (#2173)
1 parent 8d6d4c4 commit 999f815

File tree

3 files changed

+23
-23
lines changed

3 files changed

+23
-23
lines changed

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ export class McpManager {
302302
cfg: MCPServerConfig,
303303
authIntent: AuthIntent = AuthIntent.Silent
304304
): Promise<void> {
305-
const DEFAULT_SERVER_INIT_TIMEOUT_MS = 60_000
305+
const DEFAULT_SERVER_INIT_TIMEOUT_MS = 120_000
306306
this.setState(serverName, McpServerStatus.INITIALIZING, 0)
307307

308308
try {
@@ -373,7 +373,7 @@ export class McpManager {
373373
}
374374

375375
if (needsOAuth) {
376-
OAuthClient.initialize(this.features.workspace, this.features.logging)
376+
OAuthClient.initialize(this.features.workspace, this.features.logging, this.features.lsp)
377377
try {
378378
const bearer = await OAuthClient.getValidAccessToken(base, {
379379
interactive: authIntent === AuthIntent.Interactive,
@@ -382,7 +382,7 @@ export class McpManager {
382382
headers = { ...headers, Authorization: `Bearer ${bearer}` }
383383
} else if (authIntent === AuthIntent.Silent) {
384384
throw new AgenticChatError(
385-
`MCP: server '${serverName}' requires OAuth. Open "Edit MCP Server" and save to sign in.`,
385+
`Server '${serverName}' requires OAuth. Click on Save to reauthenticate.`,
386386
'MCPServerAuthFailed'
387387
)
388388
}

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ const fakeLogger = {
1919
error: () => {},
2020
}
2121

22+
const fakeLsp = {
23+
window: {
24+
showDocument: sinon.stub().resolves({ success: true }),
25+
},
26+
} as any
27+
2228
const fakeWorkspace = {
2329
fs: {
2430
exists: async (_path: string) => false,
@@ -93,9 +99,10 @@ describe('OAuthClient getValidAccessToken()', () => {
9399

94100
beforeEach(() => {
95101
sinon.restore()
96-
OAuthClient.initialize(fakeWorkspace, fakeLogger as any)
102+
OAuthClient.initialize(fakeWorkspace, fakeLogger as any, fakeLsp)
97103
sinon.stub(OAuthClient as any, 'computeKey').returns('testkey')
98104
stubHttpServer()
105+
;(fakeLsp.window.showDocument as sinon.SinonStub).resetHistory()
99106
})
100107

101108
afterEach(() => sinon.restore())
@@ -117,6 +124,6 @@ describe('OAuthClient getValidAccessToken()', () => {
117124
interactive: true,
118125
})
119126
expect(token).to.equal('cached_access')
120-
expect((http.createServer as any).calledOnce).to.be.true
127+
expect((fakeLsp.window.showDocument as sinon.SinonStub).called).to.be.false
121128
})
122129
})

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { spawn } from 'child_process'
1010
import { URL, URLSearchParams } from 'url'
1111
import * as http from 'http'
1212
import * as os from 'os'
13-
import { Logger, Workspace } from '@aws/language-server-runtimes/server-interface'
13+
import { Logger, Workspace, Lsp } from '@aws/language-server-runtimes/server-interface'
1414

1515
interface Token {
1616
access_token: string
@@ -35,10 +35,12 @@ interface Registration {
3535
export class OAuthClient {
3636
private static logger: Logger
3737
private static workspace: Workspace
38+
private static lsp: Lsp
3839

39-
public static initialize(ws: Workspace, logger: Logger): void {
40+
public static initialize(ws: Workspace, logger: Logger, lsp: Lsp): void {
4041
this.workspace = ws
4142
this.logger = logger
43+
this.lsp = lsp
4244
}
4345

4446
/**
@@ -95,10 +97,11 @@ export class OAuthClient {
9597
const savedReg = await this.read<Registration>(regPath)
9698
if (savedReg) {
9799
const port = Number(new URL(savedReg.redirect_uri).port)
100+
const normalized = `http://127.0.0.1:${port}`
98101
server = http.createServer()
99102
try {
100-
await this.listen(server, port)
101-
redirectUri = savedReg.redirect_uri
103+
await this.listen(server, port, '127.0.0.1')
104+
redirectUri = normalized
102105
this.logger.info(`OAuth: reusing redirect URI ${redirectUri}`)
103106
} catch (e: any) {
104107
if (e.code === 'EADDRINUSE') {
@@ -182,9 +185,9 @@ export class OAuthClient {
182185
/** Spin up a one‑time HTTP listener on localhost:randomPort */
183186
private static async buildCallbackServer(): Promise<{ server: http.Server; redirectUri: string }> {
184187
const server = http.createServer()
185-
await this.listen(server, 0)
188+
await this.listen(server, 0, '127.0.0.1')
186189
const port = (server.address() as any).port as number
187-
return { server, redirectUri: `http://localhost:${port}` }
190+
return { server, redirectUri: `http://127.0.0.1:${port}` }
188191
}
189192

190193
/** Discover OAuth endpoints by HEAD/WWW‑Authenticate, well‑known, or fallback */
@@ -334,7 +337,7 @@ export class OAuthClient {
334337
redirectUri: string,
335338
server: http.Server
336339
): Promise<Token> {
337-
const DEFAULT_PKCE_TIMEOUT_MS = 20_000
340+
const DEFAULT_PKCE_TIMEOUT_MS = 90_000
338341
// a) generate PKCE params
339342
const verifier = this.b64url(crypto.randomBytes(32))
340343
const challenge = this.b64url(crypto.createHash('sha256').update(verifier).digest())
@@ -353,17 +356,7 @@ export class OAuthClient {
353356
state: state,
354357
}).toString()
355358

356-
const opener =
357-
process.platform === 'win32'
358-
? {
359-
cmd: 'cmd',
360-
args: ['/c', 'start', '', `"${authz.toString().replace(/"/g, '""')}"`],
361-
}
362-
: process.platform === 'darwin'
363-
? { cmd: 'open', args: [authz.toString()] }
364-
: { cmd: 'xdg-open', args: [authz.toString()] }
365-
366-
void spawn(opener.cmd, opener.args, { detached: true, stdio: 'ignore' }).unref()
359+
await this.lsp.window.showDocument({ uri: authz.toString(), external: true })
367360

368361
// c) wait for code on our loopback
369362
const waitForFlow = new Promise<{ code: string; rxState: string; err?: string; errDesc?: string }>(resolve => {

0 commit comments

Comments
 (0)