yikart/AiToEarn · error · HttpException

授权TikTok账户失败: ${error.response?.data?.error_description || e

Error message

授权TikTok账户失败: ${error.response?.data?.error_description || error.message}

What it means

An HttpException thrown by handleAuthorizationCallback when any step of processing TikTok's OAuth callback fails (token exchange, profile fetch, saving state/token). It wraps the original error, preferring TikTok's OAuth error_description from the HTTP response body, falling back to error.message. The status is propagated from the upstream response if present, otherwise 500.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.auth.service.ts:243

        tokenResponse.expires_in - 300 // 令牌过期前5分钟
      );

      // 生成系统令牌
      const userInfo = await this.userModel.findOne({ _id: userId });
      const systemTokenInfo = {
        phone: userInfo?.phone ?? '',
        id: userId,
        name: userInfo.name,
        isManager: false,
        googleId: userInfo?.googleAccount?.googleId ?? ''
      };

      const systemToken = await this.authService.generateToken(systemTokenInfo);

      return { data: systemTokenInfo };
    } catch (error) {
      this.logger.error('处理TikTok授权回调失败:', error);
      throw new HttpException(
        '授权TikTok账户失败: ' + (error.response?.data?.error_description || error.message),
        error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR
      );
    }
  }

  /**
   * 交换授权码获取令牌
   * @param code 授权码
   * @returns TikTok OAuth令牌响应
   */
  private async exchangeCodeForTokens(code: string, codeVerifier: string): Promise<TikTokOAuthTokenResponse> {
    try {
      // 构建请求体
      const params = new URLSearchParams({
        client_key: this.clientId,
        client_secret: this.clientSecret,
        code: code,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read error_description in the thrown message — it names the exact TikTok OAuth failure (e.g. invalid_request, invalid_grant) and fix that parameter.
  2. Verify TIKTOK_CLIENT_KEY, TIKTOK_CLIENT_SECRET and redirect_uri exactly match the TikTok Developers console app settings.
  3. Check that the state passed to the callback still exists in Redis before the code expires; retry the whole OAuth flow if it doesn't.
  4. Confirm the authorization code is used once and immediately — TikTok codes are single-use and short-lived.

Example fix

// before
catch (error) {
  throw new HttpException('授权TikTok账户失败: ' + (error.response?.data?.error_description || error.message), ...);
}
// after — fail fast with a specific message before the outer wrap
if (!code || !state) {
  throw new BadRequestException('code and state are required');
}
const stateData = await this.redisService.get(`tiktok:state:${state}`);
if (!stateData) {
  throw new BadRequestException('授权状态已过期,请重新发起授权');
}
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side, before hitting the callback flow
const hasCode = typeof code === 'string' && code.length > 0;
const hasState = typeof state === 'string' && state.length > 0;
if (!hasCode || !hasState) throw new Error('OAuth callback requires code and state');

Type guard

function hasTikTokErrorData(e: unknown): e is { response: { status: number; data: { error_description: string } } } {
  return typeof e === 'object' && e !== null && 'response' in e &&
    typeof (e as any).response?.data?.error_description === 'string';
}

Try / catch

try {
  await api.handleTikTokCallback(code, state);
} catch (e) {
  const desc = (e as any).response?.data?.error_description ?? (e as Error).message;
  logger.warn(`TikTok auth failed: ${desc}`);
  if (/state|expired/i.test(desc)) redirectUserToReauth();
  else showUserError('授权失败,请重试');
}

Prevention

When it happens

Trigger: TikTok redirects the user back to /tiktok/callback with a code and state, and handleAuthorizationCallback fails while calling exchangeCodeForTokens or getTikTokUserProfile — e.g. invalid/expired auth code, state not found in Redis, TikTok returning 4xx/5xx from the token or user endpoints.

Common situations: Misconfigured TIKTOK_CLIENT_KEY/CLIENT_SECRET env vars, user denying the consent screen, replaying an already-used code, state expired in Redis (short TTL), TikTok sandbox app vs live app mismatch.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/d2c7375313024579. Report an issue: GitHub.