mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 14:52:09 +03:00
fix(auth): prevent token refresh race conditions causing refresh_token_reused errors
This commit is contained in:
@@ -841,6 +841,51 @@ export async function getAccessToken(provider, credentials, log, proxyConfig: un
|
||||
return null;
|
||||
}
|
||||
|
||||
// RACE CONDITION PREVENTION:
|
||||
// If the credentials object in memory is stale (e.g. it waited in a semaphore while another
|
||||
// request refreshed the token), using its OLD refreshToken will cause the provider (e.g. OpenAI)
|
||||
// to reject it with 'refresh_token_reused' and revoke the new token family.
|
||||
// We MUST check if the DB has a newer token before proceeding with a network refresh.
|
||||
if (credentials.connectionId) {
|
||||
try {
|
||||
const { getProviderConnectionById } = await import("../../src/lib/db/providers");
|
||||
const dbConnection = await getProviderConnectionById(credentials.connectionId);
|
||||
if (
|
||||
dbConnection &&
|
||||
dbConnection.refreshToken &&
|
||||
dbConnection.refreshToken !== credentials.refreshToken
|
||||
) {
|
||||
log?.info?.(
|
||||
"TOKEN_REFRESH",
|
||||
`Stale token detected in memory for ${provider}. Using refreshed token from DB.`
|
||||
);
|
||||
|
||||
// If the DB token is not expired, we can just return it!
|
||||
const now = Date.now();
|
||||
const dbExpiresAt = dbConnection.expiresAt ? new Date(dbConnection.expiresAt).getTime() : 0;
|
||||
|
||||
if (dbExpiresAt > now + 60000) {
|
||||
// 60 seconds buffer
|
||||
log?.info?.("TOKEN_REFRESH", `DB token is still valid. Skipping OAuth refresh.`);
|
||||
return {
|
||||
accessToken: dbConnection.accessToken,
|
||||
refreshToken: dbConnection.refreshToken,
|
||||
expiresIn: dbConnection.expiresIn,
|
||||
};
|
||||
} else {
|
||||
// DB token is also expired, but it's the NEWEST one. We must use it to refresh.
|
||||
credentials.refreshToken = dbConnection.refreshToken;
|
||||
credentials.accessToken = dbConnection.accessToken;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log?.warn?.(
|
||||
"TOKEN_REFRESH",
|
||||
`Failed to check DB for stale token: ${e instanceof Error ? e.message : String(e)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const cacheKey = getRefreshCacheKey(provider, credentials.refreshToken);
|
||||
|
||||
// If a refresh is already in-flight, reuse it
|
||||
|
||||
Reference in New Issue
Block a user