yikart/AiToEarn · error · Error
授权失败
Error message
授权失败
What it means
handleAuthorizationCode wraps its whole body in try/catch and rethrows a generic Error('授权失败') for ANY failure inside: state lookup, the token exchange POST to oauth2.googleapis.com, id_token verification (verifyIdToken with audience=webClientId), database writes, and even the earlier 无效的状态码 error. The root cause is only in console output, not in the thrown error.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/youtube/youtube.auth.service.ts:325
const results = {
data:
{
accountInfo: existingAccount,
userInfo: {
"userId": userId,
"uid": googleId
}
},
msg:"success", code: 0
};
console.log("最终返回", results);
return results;
} catch (error) {
console.error('处理授权码失败:', error);
throw new Error('授权失败');
}
}
/**
* 获取YouTube频道信息并更新账号数据库
* @param userId 用户ID
* @param googleId Google ID
* @param accessToken 访问令牌
* @param refreshToken 刷新令牌
*/
private async updateYouTubeAccountInfo(
userId: string,
email: string,
googleId: string,
accessToken: string,
refreshToken: string,
expires_in: number
): Promise<void> {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Preserve the original error in the rethrow: throw new Error(`授权失败: ${error.message}`) so the API caller sees the cause.
- Check the console '处理授权码失败' log for the Google error payload (invalid_grant, redirect_uri_mismatch, invalid_client).
- Confirm GOOGLE_CONFIG.WEB_RENDER_URL-based redirect_uri exactly matches a registered redirect URI in Google Cloud Console.
- Prevent callback-page refresh/replay; each authorization code is single-use.
- Re-run the OAuth flow; if the state error is the cause, the fix is a longer state TTL (see 无效的状态码).
Example fix
// before
} catch (error) {
console.error('处理授权码失败:', error);
throw new Error('授权失败');
}
// after
} catch (error) {
console.error('处理授权码失败:', error);
if (error instanceof Error && error.message === '无效的状态码') throw error
throw new Error(`授权失败: ${error?.response?.data?.error || error.message}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before exchange: validate inputs and that the code is single-use fresh
if (!code || !state || !userId) throw new Error('missing code/state/userId for authorization callback')
const stateInfo = await redisService.get(`youtube:state:${userId}:${state}`)
if (!stateInfo?.mail) throw new Error('state expired') Type guard
const isGoogleTokenError = (e: unknown): e is { response: { status: number; data: { error: string; error_description?: string } } } =>
typeof e === 'object' && e !== null &&
typeof (e as any).response?.data?.error === 'string' Try / catch
try {
return await youtubeAuthService.handleAuthorizationCode(code, state, userId)
} catch (e) {
if (isGoogleTokenError(e)) {
const { error, error_description } = e.response.data
if (error === 'invalid_grant') return restartOAuthFlow() // code used/expired
if (error === 'redirect_uri_mismatch') return fixRedirectUriConfig()
}
if (e.message === '无效的状态码') return restartOAuthFlow()
throw e
} Prevention
- Register the exact redirect_uri in Google Cloud Console and keep WEB_RENDER_URL consistent
- Never re-run the callback with the same authorization code (single-use)
- Unwrap errors before rethrowing so logs and API responses show the root cause
- Distinguish the state-check error from token-exchange errors in the catch block
- Keep WEB_CLIENT_SECRET in sync with the client that initiated consent
When it happens
Trigger: Authorization code already used or expired (Google token endpoint returns 400 invalid_grant), redirect_uri mismatch between callback request and the token exchange params, GOOGLE_CONFIG.WEB_CLIENT_SECRET wrong, verifyIdToken failing because id_token audience differs from webClientId, or the earlier state-check throw bubbling here.
Common situations: The web render callback URL not registered as an authorized redirect URI in Google Cloud Console; user refreshing the callback page (code reuse); environment mismatch where the token was issued to a different OAuth client; Redis state expired as in the 无效的状态码 path.
Related errors
- Google login failed: ${error.message}
- Invalid Google token
- Failed to refresh access token
- Failed to get user permissions
- Failed to fetch user info
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/4b44680809aaeb6d.
Report an issue: GitHub.