Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/opencode/src/plugin/openai/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,16 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug
return {
apiKey: OAUTH_DUMMY_KEY,
async fetch(requestInput: RequestInfo | URL, init?: RequestInit) {
const currentAuth = await getAuth()
if (currentAuth?.type === "api") {
const headers = new Headers(init?.headers)
headers.set("authorization", `Bearer ${currentAuth.key}`)
const requestInit = { ...init, headers }
return websocketFetch ? websocketFetch(requestInput, requestInit) : fetch(requestInput, requestInit)
}
if (currentAuth?.type !== "oauth")
return websocketFetch ? websocketFetch(requestInput, init) : fetch(requestInput, init)

if (init?.headers) {
if (init.headers instanceof Headers) {
init.headers.delete("authorization")
Expand All @@ -352,10 +362,6 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug
}
}

const currentAuth = await getAuth()
if (currentAuth.type !== "oauth")
return websocketFetch ? websocketFetch(requestInput, init) : fetch(requestInput, init)

const authWithAccount = currentAuth as typeof currentAuth & { accountId?: string }

if (!currentAuth.access || currentAuth.expires < Date.now()) {
Expand Down
63 changes: 63 additions & 0 deletions packages/opencode/test/plugin/codex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
renderOAuthError,
type IdTokenClaims,
} from "../../src/plugin/openai/codex"
import { OAUTH_DUMMY_KEY } from "../../src/auth"

function createTestJwt(payload: object): string {
const header = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url")
Expand Down Expand Up @@ -149,6 +150,68 @@ describe("plugin.codex", () => {
await enabled.dispose?.()
})

test("passes requests through when OAuth auth is removed after loading", async () => {
let auth:
| {
type: "oauth"
refresh: string
access: string
expires: number
}
| undefined = {
type: "oauth",
refresh: "refresh",
access: "access",
expires: Date.now() + 60_000,
}
using server = Bun.serve({
port: 0,
fetch(request) {
return Response.json({ authorization: request.headers.get("authorization") })
},
})
const hooks = await CodexAuthPlugin({} as never)
const loaded = await hooks.auth!.loader!(async () => auth as never, {} as never)
auth = undefined

const response = await loaded.fetch!(server.url, {
headers: { authorization: `Bearer ${OAUTH_DUMMY_KEY}` },
})

expect(await response.json()).toEqual({ authorization: `Bearer ${OAUTH_DUMMY_KEY}` })
})

test("uses current API key when OAuth auth is replaced after loading", async () => {
let auth:
| {
type: "oauth"
refresh: string
access: string
expires: number
}
| { type: "api"; key: string } = {
type: "oauth",
refresh: "refresh",
access: "access",
expires: Date.now() + 60_000,
}
using server = Bun.serve({
port: 0,
fetch(request) {
return Response.json({ authorization: request.headers.get("authorization") })
},
})
const hooks = await CodexAuthPlugin({} as never)
const loaded = await hooks.auth!.loader!(async () => auth as never, {} as never)
auth = { type: "api", key: "sk-current" }

const response = await loaded.fetch!(server.url, {
headers: { authorization: `Bearer ${OAUTH_DUMMY_KEY}` },
})

expect(await response.json()).toEqual({ authorization: "Bearer sk-current" })
})

test("filters unsupported modes and uses Codex context limits for OAuth GPT models", async () => {
const hooks = await CodexAuthPlugin({} as never)
const limit = { context: 1_050_000, input: 922_000, output: 128_000 }
Expand Down
Loading