fix: await saveCredentialsForProfile inside .then() callback to prevent race condition

Move saveCredentialsForProfile calls inside the .then() callbacks and make
them async/await to ensure credentials are saved as part of the promise
chain. This prevents race conditions when multiple concurrent requests
share the same refresh promise.
This commit is contained in:
Roo Code 2026-01-30 02:53:34 +00:00
parent 2e924c61b3
commit a0d547034c

View file

@ -490,13 +490,17 @@ export class OpenAiCodexOAuthManager {
`[openai-codex-oauth] Access token expired for profile ${profileId || "global"} (expires=${credentials.expires}). Refreshing...`,
)
const prevRefreshToken = credentials.refresh_token
refreshPromise = refreshAccessToken(credentials).then((newCreds) => {
refreshPromise = refreshAccessToken(credentials).then(async (newCreds) => {
const rotated = newCreds.refresh_token !== prevRefreshToken
this.log(
`[openai-codex-oauth] Refresh response received for profile ${profileId || "global"} (expires_in≈${Math.round(
(newCreds.expires - Date.now()) / 1000,
)}s, refresh_token_rotated=${rotated})`,
)
await this.saveCredentialsForProfile(newCreds, profileId)
this.log(
`[openai-codex-oauth] Token persisted for profile ${profileId || "global"} (expires=${newCreds.expires})`,
)
return newCreds
})
this.refreshPromises.set(cacheKey, refreshPromise)
@ -504,10 +508,6 @@ export class OpenAiCodexOAuthManager {
const newCredentials = await refreshPromise
this.refreshPromises.delete(cacheKey)
await this.saveCredentialsForProfile(newCredentials, profileId)
this.log(
`[openai-codex-oauth] Token persisted for profile ${profileId || "global"} (expires=${newCredentials.expires})`,
)
credentials = newCredentials
} catch (error) {
this.refreshPromises.delete(cacheKey)
@ -553,13 +553,17 @@ export class OpenAiCodexOAuthManager {
this.log(
`[openai-codex-oauth] Forcing token refresh for profile ${profileId || "global"} (expires=${credentials.expires})...`,
)
refreshPromise = refreshAccessToken(credentials).then((newCreds) => {
refreshPromise = refreshAccessToken(credentials).then(async (newCreds) => {
const rotated = newCreds.refresh_token !== prevRefreshToken
this.log(
`[openai-codex-oauth] Forced refresh response received for profile ${profileId || "global"} (expires_in≈${Math.round(
(newCreds.expires - Date.now()) / 1000,
)}s, refresh_token_rotated=${rotated})`,
)
await this.saveCredentialsForProfile(newCreds, profileId)
this.log(
`[openai-codex-oauth] Forced token persisted for profile ${profileId || "global"} (expires=${newCreds.expires})`,
)
return newCreds
})
this.refreshPromises.set(cacheKey, refreshPromise)
@ -567,10 +571,6 @@ export class OpenAiCodexOAuthManager {
const newCredentials = await refreshPromise
this.refreshPromises.delete(cacheKey)
await this.saveCredentialsForProfile(newCredentials, profileId)
this.log(
`[openai-codex-oauth] Forced token persisted for profile ${profileId || "global"} (expires=${newCredentials.expires})`,
)
return newCredentials.access_token
} catch (error) {
this.refreshPromises.delete(cacheKey)