Route OpenAI OAuth callback through desktop server

The ChatGPT Official OAuth start flow already generated the Codex /auth/callback redirect, but the desktop server only handled the older /callback/openai path. Real HTTP and UI E2E exposed the mismatch, so the server now routes the Codex callback path while retaining the legacy alias.

Constraint: OpenAI Codex OAuth client code owns OPENAI_CODEX_REDIRECT_PATH.

Rejected: Change the generated redirect back to /callback/openai | that would diverge from the shared OpenAI Codex OAuth client path.

Confidence: high

Scope-risk: narrow

Tested: bun test src/server/__tests__/providers.test.ts src/server/__tests__/settings.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/proxy-transform.test.ts src/utils/__tests__/providerManagedEnvCompat.test.ts src/services/api/client.test.ts src/services/openaiAuth/fetch.test.ts src/server/__tests__/haha-openai-oauth-service.test.ts src/server/__tests__/haha-openai-oauth-api.test.ts

Tested: HTTP E2E passed at /var/folders/sx/hl8zlmxd7gx9b58_1t2zhp5r0000gn/T/cc-haha-openai-oauth-e2e-4uWfok/result.json.

Tested: UI E2E passed at /var/folders/sx/hl8zlmxd7gx9b58_1t2zhp5r0000gn/T/cc-haha-openai-oauth-ui-e2e-ZyQ60q/result.json.
This commit is contained in:
程序员阿江(Relakkes) 2026-05-19 18:50:06 +08:00
parent 9e45724290
commit 5b0ab7aa8a
3 changed files with 47 additions and 2 deletions

View File

@ -6,8 +6,11 @@ import { describe, test, expect, beforeEach, afterEach } from 'bun:test'
import * as fs from 'fs/promises'
import * as path from 'path'
import * as os from 'os'
import { createServer } from 'net'
import { handleHahaOpenAIOAuthApi } from '../api/haha-openai-oauth.js'
import { hahaOpenAIOAuthService } from '../services/hahaOpenAIOAuthService.js'
import { startServer } from '../index.js'
import { ProviderService } from '../services/providerService.js'
let tmpDir: string
let originalConfigDir: string | undefined
@ -44,6 +47,22 @@ function buildReq(
return { req, url, segments }
}
async function getFreePort(): Promise<number> {
return await new Promise((resolve, reject) => {
const server = createServer()
server.on('error', reject)
server.listen(0, '127.0.0.1', () => {
const address = server.address()
if (!address || typeof address === 'string') {
server.close(() => reject(new Error('Failed to allocate test port')))
return
}
const port = address.port
server.close(() => resolve(port))
})
})
}
describe('POST /api/haha-openai-oauth/start', () => {
beforeEach(setup)
afterEach(teardown)
@ -157,3 +176,24 @@ describe('DELETE /api/haha-openai-oauth', () => {
expect(await hahaOpenAIOAuthService.loadTokens()).toBeNull()
})
})
describe('GET /auth/callback', () => {
beforeEach(setup)
afterEach(teardown)
test('routes the OpenAI Codex redirect path to the desktop callback page', async () => {
const port = await getFreePort()
const originalServerPort = ProviderService.getServerPort()
const server = startServer(port, '127.0.0.1')
try {
const res = await fetch(`http://127.0.0.1:${port}/auth/callback`)
expect(res.status).toBe(200)
const html = await res.text()
expect(html).toContain('OpenAI Login Failed')
expect(html).toContain('Missing code or state parameter')
} finally {
server.stop(true)
ProviderService.setServerPort(originalServerPort)
}
})
})

View File

@ -2,7 +2,8 @@
* Haha OpenAI OAuth REST API
*
* POST /api/haha-openai-oauth/start PKCE+state, authorize URL
* GET /callback/openai redirect , token
* GET /auth/callback redirect , token
* GET /callback/openai
* GET /api/haha-openai-oauth ( token )
* DELETE /api/haha-openai-oauth , token
*/

View File

@ -15,6 +15,7 @@ import { handleProxyRequest } from './proxy/handler.js'
import { ProviderService } from './services/providerService.js'
import { handleHahaOAuthCallback } from './api/haha-oauth.js'
import { handleHahaOpenAIOAuthCallback } from './api/haha-openai-oauth.js'
import { OPENAI_CODEX_REDIRECT_PATH } from '../services/openaiAuth/client.js'
import { ensureDesktopCliLauncherInstalled } from './services/desktopCliLauncherService.js'
import { enableConfigs } from '../utils/config.js'
import { diagnosticsService } from './services/diagnosticsService.js'
@ -267,7 +268,10 @@ export function startServer(port = PORT, host = HOST) {
return handleHahaOAuthCallback(url)
}
if (url.pathname === '/callback/openai') {
if (
url.pathname === OPENAI_CODEX_REDIRECT_PATH ||
url.pathname === '/callback/openai'
) {
return handleHahaOpenAIOAuthCallback(url)
}