Skip to content

refactor: replace Bun.serve with Node http.createServer in OAuth handlers#18327

Open
thdxr wants to merge 2 commits intodevfrom
refactor/oauth-node-http
Open

refactor: replace Bun.serve with Node http.createServer in OAuth handlers#18327
thdxr wants to merge 2 commits intodevfrom
refactor/oauth-node-http

Conversation

@thdxr
Copy link
Member

@thdxr thdxr commented Mar 20, 2026

Summary

  • Replace Bun.serve with http.createServer in MCP OAuth callback server
  • Replace Bun.serve with http.createServer in Codex plugin OAuth server
  • Both use the same pattern: express-style request handlers with res.writeHead/res.end

…lers

Use Node's createServer for MCP OAuth callback and Codex plugin OAuth
servers instead of Bun.serve, making them work under Node.js.
thdxr added a commit that referenced this pull request Mar 20, 2026
@greptile-apps
Copy link

greptile-apps bot commented Mar 20, 2026

Greptile Summary

This PR refactors both OAuth servers — in mcp/oauth-callback.ts and plugin/codex.ts — to replace Bun.serve with Node.js http.createServer, aligning them with a more portable, runtime-agnostic pattern. The core request-handling logic is preserved faithfully; writeHead/end replace new Response(...) and server lifecycle is wrapped in Promises.

Key observations:

  • Note that AGENTS.md explicitly states "Use Bun APIs when possible". Replacing Bun.serve with Node.js HTTP goes against this guideline. If this is a deliberate step toward making opencode runtime-agnostic (e.g. for Node.js compatibility), that rationale should be documented.
  • packages/opencode/src/mcp/oauth-callback.ts: The migration is clean. stop() correctly awaits server.close() before clearing the reference, ensuring the port is fully released.
  • packages/opencode/src/plugin/codex.ts: stopOAuthServer sets oauthServer = undefined synchronously while server.close() is asynchronous. This creates a race condition: a subsequent startOAuthServer() call may attempt to listen() on a port that is still bound, resulting in an EADDRINUSE error. This is an inconsistency with how oauth-callback.ts handles the same teardown.

Confidence Score: 3/5

  • Mostly safe, but the async teardown race in codex.ts stopOAuthServer could cause EADDRINUSE on rapid re-authentication
  • The oauth-callback.ts migration is correct and the logic is functionally equivalent to the Bun.serve version. However, codex.ts has a real teardown race condition introduced by this refactor that wasn't present with Bun.serve's synchronous stop(), and the change contradicts the AGENTS.md "Use Bun APIs when possible" guideline without explanation.
  • packages/opencode/src/plugin/codex.ts — specifically the stopOAuthServer function at line 324

Important Files Changed

Filename Overview
packages/opencode/src/mcp/oauth-callback.ts Bun.serve replaced with http.createServer; logic is functionally equivalent, stop() correctly awaits close, minor style issue with inline import types in handleRequest signature
packages/opencode/src/plugin/codex.ts Bun.serve replaced with http.createServer; stopOAuthServer sets oauthServer to undefined synchronously while close() is async, creating a race condition if startOAuthServer is called before the port is fully released

Sequence Diagram

sequenceDiagram
    participant App
    participant Server as http.createServer
    participant Handler as Request Handler
    participant Pending as pendingOAuth/pendingAuths

    App->>Server: createServer(handler) + listen(PORT)
    Note over Server: Listening on PORT

    App->>Pending: waitForOAuthCallback(state)
    Note over App: Browser redirected to localhost

    Server->>Handler: GET /auth/callback?code=X&state=Y
    Handler->>Pending: resolve(code or tokens)
    Handler->>Server: res.writeHead(200) + res.end(HTML_SUCCESS)

    alt codex.ts stopOAuthServer
        App->>Server: server.close(cb) — async
        App->>App: oauthServer = undefined — SYNC (race!)
        Note over Server: Port may still be bound when next startOAuthServer runs
    else oauth-callback.ts stop
        App->>Server: await server.close(cb)
        Note over Server: Port released before returning
        App->>App: server = undefined
    end
Loading

Last reviewed commit: "refactor: replace Bu..."

Comment on lines 324 to 331
function stopOAuthServer() {
if (oauthServer) {
oauthServer.stop()
oauthServer.close(() => {
log.info("codex oauth server stopped")
})
oauthServer = undefined
log.info("codex oauth server stopped")
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Race condition: port still in use after stopOAuthServer returns

oauthServer is set to undefined synchronously, but server.close() in Node.js is asynchronous — the underlying port is only released once the close callback fires. If startOAuthServer() is called again before that callback fires (e.g. the user immediately re-initiates auth), oauthServer is undefined so the early-return guard is bypassed, and the new listen() call will fail with EADDRINUSE.

By contrast, Bun.serve.stop() released the port synchronously. The sibling McpOAuthCallback.stop() correctly awaits the close before clearing the reference:

await new Promise<void>((resolve) => server!.close(() => resolve()))
server = undefined

stopOAuthServer should follow the same pattern (make it async and await the close) or at minimum only clear oauthServer inside the close callback:

function stopOAuthServer() {
  if (oauthServer) {
    const closing = oauthServer
    oauthServer = undefined
    closing.close(() => {
      log.info("codex oauth server stopped")
    })
  }
}

Note: even the snippet above doesn't fully close the port before returning. If true synchronous-style safety is needed, the function should be made async and awaited at the call site.


export async function ensureRunning(): Promise<void> {
if (server) return
function handleRequest(req: import("http").IncomingMessage, res: import("http").ServerResponse) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Inline dynamic import types are unnecessary

import("http").IncomingMessage and import("http").ServerResponse are used as inline type expressions, but http is already imported at line 2. The types can be imported alongside createServer to keep the signature readable.

Suggested change
function handleRequest(req: import("http").IncomingMessage, res: import("http").ServerResponse) {
function handleRequest(req: import("http").IncomingMessage, res: import("http").ServerResponse) {

Change the top-level import to:

import { createServer, type IncomingMessage, type ServerResponse } from "http"

Then the function signature becomes:

function handleRequest(req: IncomingMessage, res: ServerResponse) {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@thdxr thdxr added the beta label Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
@thdxr thdxr added beta and removed beta labels Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
@thdxr thdxr added beta and removed beta labels Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 20, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 21, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
opencode-agent bot added a commit that referenced this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant