fix(auth): refresh all OAuth profiles per provider
Previously, resolveOAuthToken() would return after finding the first valid profile for a provider, leaving other profiles expired. This caused multi-account setups to only refresh one account per provider. Additionally, the status display would show stale expiry times because it read credentials before the usage fetch triggered refreshes. Changes: - Renamed resolveOAuthToken() to resolveOAuthTokens() and changed it to collect all valid profiles instead of returning early - Updated resolveProviderAuths() to spread all resolved tokens - Added store re-read in list.status-command.ts after usage fetch to display refreshed credential state Fixes #3803
This commit is contained in:
parent
4583f88626
commit
7dad13cd3a
@ -14,6 +14,7 @@ Status: beta.
|
||||
- Memory Search: allow extra paths for memory indexing. (#3600) Thanks @kira-ariaki.
|
||||
|
||||
### Changes
|
||||
- Auth: fix OAuth refresh only refreshing one profile per provider, leaving other accounts expired. (#3803)
|
||||
- Providers: add Venice AI integration; update Moonshot Kimi references to kimi-k2.5; update MiniMax API endpoint/format. (#2762, #3064)
|
||||
- Providers: add Xiaomi MiMo (mimo-v2-flash) support and onboarding flow. (#3454) Thanks @WqyJh.
|
||||
- Telegram: quote replies, edit-message action, silent sends, sticker support + vision caching, linkPreview toggle, plugin sendPayload support. (#2900, #2394, #2382, #2548, #1700, #1917)
|
||||
|
||||
@ -528,6 +528,18 @@ export async function modelsStatusCommand(
|
||||
}
|
||||
}
|
||||
|
||||
// Re-read auth health after usage fetch, which may have refreshed expired tokens
|
||||
const refreshedStore = ensureAuthProfileStore();
|
||||
const refreshedHealth = buildAuthHealthSummary({
|
||||
store: refreshedStore,
|
||||
cfg,
|
||||
warnAfterMs: DEFAULT_OAUTH_WARN_MS,
|
||||
providers,
|
||||
});
|
||||
const refreshedOauthProfiles = refreshedHealth.profiles.filter(
|
||||
(profile) => profile.type === "oauth" || profile.type === "token",
|
||||
);
|
||||
|
||||
const formatStatus = (status: string) => {
|
||||
if (status === "ok") return colorize(rich, theme.success, "ok");
|
||||
if (status === "static") return colorize(rich, theme.muted, "static");
|
||||
@ -536,8 +548,8 @@ export async function modelsStatusCommand(
|
||||
return colorize(rich, theme.error, "expired");
|
||||
};
|
||||
|
||||
const profilesByProvider = new Map<string, typeof oauthProfiles>();
|
||||
for (const profile of oauthProfiles) {
|
||||
const profilesByProvider = new Map<string, typeof refreshedOauthProfiles>();
|
||||
for (const profile of refreshedOauthProfiles) {
|
||||
const current = profilesByProvider.get(profile.provider);
|
||||
if (current) current.push(profile);
|
||||
else profilesByProvider.set(profile.provider, [profile]);
|
||||
|
||||
@ -123,10 +123,10 @@ function resolveXiaomiApiKey(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function resolveOAuthToken(params: {
|
||||
async function resolveOAuthTokens(params: {
|
||||
provider: UsageProviderId;
|
||||
agentDir?: string;
|
||||
}): Promise<ProviderAuth | null> {
|
||||
}): Promise<ProviderAuth[]> {
|
||||
const cfg = loadConfig();
|
||||
const store = ensureAuthProfileStore(params.agentDir, {
|
||||
allowKeychainPrompt: false,
|
||||
@ -143,6 +143,7 @@ async function resolveOAuthToken(params: {
|
||||
if (!deduped.includes(entry)) deduped.push(entry);
|
||||
}
|
||||
|
||||
const results: ProviderAuth[] = [];
|
||||
for (const profileId of deduped) {
|
||||
const cred = store.profiles[profileId];
|
||||
if (!cred || (cred.type !== "oauth" && cred.type !== "token")) continue;
|
||||
@ -161,20 +162,20 @@ async function resolveOAuthToken(params: {
|
||||
const parsed = parseGoogleToken(resolved.apiKey);
|
||||
token = parsed?.token ?? resolved.apiKey;
|
||||
}
|
||||
return {
|
||||
results.push({
|
||||
provider: params.provider,
|
||||
token,
|
||||
accountId:
|
||||
cred.type === "oauth" && "accountId" in cred
|
||||
? (cred as { accountId?: string }).accountId
|
||||
: undefined,
|
||||
};
|
||||
});
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return results;
|
||||
}
|
||||
|
||||
function resolveOAuthProviders(agentDir?: string): UsageProviderId[] {
|
||||
@ -233,11 +234,11 @@ export async function resolveProviderAuths(params: {
|
||||
}
|
||||
|
||||
if (!oauthProviders.includes(provider)) continue;
|
||||
const auth = await resolveOAuthToken({
|
||||
const resolved = await resolveOAuthTokens({
|
||||
provider,
|
||||
agentDir: params.agentDir,
|
||||
});
|
||||
if (auth) auths.push(auth);
|
||||
auths.push(...resolved);
|
||||
}
|
||||
|
||||
return auths;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user