From 92a550973aa19818616f77d06c112b502c7554e5 Mon Sep 17 00:00:00 2001 From: hank Date: Tue, 25 Aug 2026 16:52:29 +0800 Subject: [PATCH] fix(accounts): reauthorize OpenAI with refresh token --- .../admin/account/ReAuthAccountModal.vue | 70 ++++++++++++++++++- .../__tests__/ReAuthAccountModal.grok.spec.ts | 3 +- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/admin/account/ReAuthAccountModal.vue b/frontend/src/components/admin/account/ReAuthAccountModal.vue index f13876fe60..5a9b6f62ef 100644 --- a/frontend/src/components/admin/account/ReAuthAccountModal.vue +++ b/frontend/src/components/admin/account/ReAuthAccountModal.vue @@ -140,7 +140,7 @@ :initial-input-method="grokInitialInputMethod" @generate-url="handleGenerateUrl" @cookie-auth="handleCookieAuth" - @validate-refresh-token="handleGrokValidateRefreshToken" + @validate-refresh-token="handleValidateRefreshToken" @import-sso="handleGrokImportSSO" /> @@ -626,6 +626,74 @@ const applyGrokReauthTokenInfo = async (tokenInfo: { handleClose() } +/** Re-auth the existing account with one refresh token. */ +const handleValidateRefreshToken = async (refreshTokenInput: string) => { + if (!props.account) return + if (isGrok.value) { + await handleGrokValidateRefreshToken(refreshTokenInput) + return + } + + const refreshToken = refreshTokenInput + .split('\n') + .map((line) => line.trim()) + .filter(Boolean)[0] + if (!refreshToken) return + + if (isOpenAILike.value) { + openaiOAuth.loading.value = true + openaiOAuth.error.value = '' + try { + const tokenInfo = await openaiOAuth.validateRefreshToken(refreshToken, props.account.proxy_id) + if (!tokenInfo) return + + const updatedAccount = await adminAPI.accounts.applyOAuthCredentials(props.account.id, { + type: 'oauth', + credentials: openaiOAuth.buildCredentials(tokenInfo), + extra: openaiOAuth.buildExtraInfo(tokenInfo) + }) + appStore.showSuccess(t('admin.accounts.reAuthorizedSuccess')) + emit('reauthorized', updatedAccount) + handleClose() + } catch (error: any) { + openaiOAuth.error.value = + error.response?.data?.detail || + error.response?.data?.message || + error.message || + t('admin.accounts.oauth.authFailed') + appStore.showError(openaiOAuth.error.value) + } finally { + openaiOAuth.loading.value = false + } + return + } + + if (!isAntigravity.value) return + antigravityOAuth.loading.value = true + antigravityOAuth.error.value = '' + try { + const tokenInfo = await antigravityOAuth.validateRefreshToken(refreshToken, props.account.proxy_id) + if (!tokenInfo) return + + const updatedAccount = await adminAPI.accounts.applyOAuthCredentials(props.account.id, { + type: 'oauth', + credentials: antigravityOAuth.buildCredentials(tokenInfo, refreshToken) + }) + appStore.showSuccess(t('admin.accounts.reAuthorizedSuccess')) + emit('reauthorized', updatedAccount) + handleClose() + } catch (error: any) { + antigravityOAuth.error.value = + error.response?.data?.detail || + error.response?.data?.message || + error.message || + t('admin.accounts.oauth.authFailed') + appStore.showError(antigravityOAuth.error.value) + } finally { + antigravityOAuth.loading.value = false + } +} + /** Re-auth with a single SSO cookie → Build OAuth (not batch create). */ const handleGrokImportSSO = async (ssoInput: string) => { if (!props.account || !isGrok.value) return diff --git a/frontend/src/components/admin/account/__tests__/ReAuthAccountModal.grok.spec.ts b/frontend/src/components/admin/account/__tests__/ReAuthAccountModal.grok.spec.ts index 87dbf5d1e4..02cb862d0a 100644 --- a/frontend/src/components/admin/account/__tests__/ReAuthAccountModal.grok.spec.ts +++ b/frontend/src/components/admin/account/__tests__/ReAuthAccountModal.grok.spec.ts @@ -17,7 +17,8 @@ describe('ReAuthAccountModal Grok re-auth paths', () => { it('wires SSO and RT reauth without batch account create', () => { expect(source).toContain('@import-sso="handleGrokImportSSO"') - expect(source).toContain('@validate-refresh-token="handleGrokValidateRefreshToken"') + expect(source).toContain('@validate-refresh-token="handleValidateRefreshToken"') + expect(source).toContain('await handleGrokValidateRefreshToken(refreshTokenInput)') expect(source).toContain('grokOAuth.validateSSOToken') expect(source).toContain('grokOAuth.buildCredentials') // Re-auth updates the existing account; must not call createFromSSO batch create