@@ -10,12 +10,18 @@ export function codexConfigPath(home: string = homedir()): string {
1010 return join ( home , '.codex' , 'config.toml' ) ;
1111}
1212
13+ export function codexAuthPath ( home : string = homedir ( ) ) : string {
14+ return join ( home , '.codex' , 'auth.json' ) ;
15+ }
16+
1317export interface CodexImport {
1418 providers : ProviderEntry [ ] ;
1519 activeProvider : string | null ;
1620 activeModel : string | null ;
1721 /** Env-key lookups the caller should run to resolve keys. */
1822 envKeyMap : Record < string , string > ; // providerId → envVarName
23+ /** API keys resolved from Codex auth.json, keyed by imported provider id. */
24+ apiKeyMap : Record < string , string > ;
1925 warnings : string [ ] ;
2026}
2127
@@ -25,6 +31,7 @@ type CodexProviderBlock = {
2531 env_key ?: string ;
2632 model ?: string ;
2733 wire_api ?: string ;
34+ requires_openai_auth ?: boolean ;
2835 http_headers ?: Record < string , string > ;
2936 query_params ?: Record < string , string > ;
3037} ;
@@ -49,6 +56,7 @@ export async function parseCodexConfig(toml: string): Promise<CodexImport> {
4956 activeProvider : null ,
5057 activeModel : null ,
5158 envKeyMap : { } ,
59+ apiKeyMap : { } ,
5260 warnings : [ `Codex config.toml is not valid TOML: ${ msg } ` ] ,
5361 } ;
5462 }
@@ -59,6 +67,7 @@ export async function parseCodexConfig(toml: string): Promise<CodexImport> {
5967 activeProvider : null ,
6068 activeModel : null ,
6169 envKeyMap : { } ,
70+ apiKeyMap : { } ,
6271 warnings : [ 'Codex config.toml has unexpected top-level shape' ] ,
6372 } ;
6473 }
@@ -109,6 +118,9 @@ export async function parseCodexConfig(toml: string): Promise<CodexImport> {
109118 entry . envKey = block . env_key ;
110119 envKeyMap [ entry . id ] = block . env_key ;
111120 }
121+ if ( block . requires_openai_auth === true ) {
122+ entry . requiresApiKey = true ;
123+ }
112124 if ( block . http_headers !== undefined && typeof block . http_headers === 'object' ) {
113125 const map : Record < string , string > = { } ;
114126 for ( const [ k , v ] of Object . entries ( block . http_headers ) ) {
@@ -135,7 +147,34 @@ export async function parseCodexConfig(toml: string): Promise<CodexImport> {
135147 if ( entry !== undefined ) entry . defaultModel = activeModel ;
136148 }
137149
138- return { providers, activeProvider : activeProviderId , activeModel, envKeyMap, warnings } ;
150+ return {
151+ providers,
152+ activeProvider : activeProviderId ,
153+ activeModel,
154+ envKeyMap,
155+ apiKeyMap : { } ,
156+ warnings,
157+ } ;
158+ }
159+
160+ async function readCodexOpenAiApiKey ( home : string = homedir ( ) ) : Promise < string | null > {
161+ let raw : string ;
162+ try {
163+ raw = await readFile ( codexAuthPath ( home ) , 'utf8' ) ;
164+ } catch ( err ) {
165+ if ( ( err as NodeJS . ErrnoException ) . code === 'ENOENT' ) return null ;
166+ throw err ;
167+ }
168+ let parsed : unknown ;
169+ try {
170+ parsed = JSON . parse ( raw ) ;
171+ } catch {
172+ return null ;
173+ }
174+ if ( typeof parsed !== 'object' || parsed === null || Array . isArray ( parsed ) ) return null ;
175+ const record = parsed as Record < string , unknown > ;
176+ const rawKey = record [ 'OPENAI_API_KEY' ] ?? record [ 'openai_api_key' ] ?? record [ 'apiKey' ] ;
177+ return typeof rawKey === 'string' && rawKey . trim ( ) . length > 0 ? rawKey . trim ( ) : null ;
139178}
140179
141180export async function readCodexConfig ( home : string = homedir ( ) ) : Promise < CodexImport | null > {
@@ -147,5 +186,15 @@ export async function readCodexConfig(home: string = homedir()): Promise<CodexIm
147186 if ( ( err as NodeJS . ErrnoException ) . code === 'ENOENT' ) return null ;
148187 throw err ;
149188 }
150- return parseCodexConfig ( raw ) ;
189+ const imported = await parseCodexConfig ( raw ) ;
190+ const openAiApiKey = await readCodexOpenAiApiKey ( home ) ;
191+ if ( openAiApiKey === null ) return imported ;
192+
193+ const apiKeyMap : Record < string , string > = { } ;
194+ for ( const provider of imported . providers ) {
195+ if ( provider . requiresApiKey === true ) {
196+ apiKeyMap [ provider . id ] = openAiApiKey ;
197+ }
198+ }
199+ return { ...imported , apiKeyMap } ;
151200}
0 commit comments