{"record":{"id":"96136d7de4111ad5","repo":"yikart/AiToEarn","slug":"error-96136d","errorCode":null,"errorMessage":"缺少必要的参数","messagePattern":"缺少必要的参数","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts","lineNumber":53,"sourceCode":"    return this.tikTokAuthService.getAuthorizationUrl(systemToken.id, mail);\n  }\n\n  /**\n   * TikTok OAuth2回调处理\n   */\n\n  @ApiOperation({ summary: 'TikTok OAuth2回调处理' })\n  @Public()\n  @ApiQuery({ name: 'code', type: String, description: 'OAuth2授权码' })\n  @ApiQuery({ name: 'state', type: String, description: '状态码' })\n  @Get('auth/callback')\n  async handleAuthCallback(\n    @Query('code') code: string,\n    @Query('state') state: string,\n    @Res() res: Response,\n  ) {\n    if (!code || !state) {\n      throw new BadRequestException('缺少必要的参数');\n    }\n    console.log(code, state);\n\n    try {\n      // 处理授权回调\n      const results = await this.tikTokAuthService.handleAuthorizationCallback(code, state);\n      const render_msg = {\n        message: \"授权成功！ 这里是添加账号成功后的前端页面，\" ,\n        datas: results\n      };\n\n      return res.render('google/index', render_msg);\n    } catch (error) {\n      console.error('处理TikTok授权回调失败:', error.response?.data || error.message);\n      throw new BadRequestException(`处理授权回调失败: ${error.response?.data?.error?.message || error.message}`);\n    }\n  }\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts#L35-L71","documentation":"A BadRequestException raised by the handleAuthCallback controller when TikTok's redirect to the callback URL omits the code or state query parameters. Both are required: code exchanges for tokens, state correlates the request with the pending authorization in Redis.","triggerScenarios":"The user lands on /tiktok/callback without ?code=...&state=... — e.g. the user cancelled/failed consent so TikTok redirects back with error parameters instead of code, the redirect_uri's query handling strips parameters, or someone hits the callback URL manually.","commonSituations":"User denied permission on TikTok's consent screen (redirect contains error=access_denied, no code), bookmarked/stale callback link, redirect_uri registered with a query string that collides with OAuth parameters, proxy rewriting the URL.","solutions":["Inspect the callback URL for error/error_description query params (user denied access) and handle them with a friendly message before checking code/state.","Re-initiate the OAuth flow from /tiktok/auth-url to get a fresh code and state.","Verify the redirect_uri registered on the TikTok app has no conflicting query string and that the server does not strip query params.","On the client, never call the callback endpoint directly; always follow TikTok's redirect."],"exampleFix":"// before\nif (!code || !state) {\n  throw new BadRequestException('缺少必要的参数');\n}\n// after\nif (error) {\n  return res.redirect(`/oauth/result?status=denied&reason=${encodeURIComponent(error_description || error)}`);\n}\nif (!code || !state) {\n  return res.redirect('/oauth/result?status=failed&reason=missing_params');\n}","handlingStrategy":"validation","validationCode":"// on the callback page, before invoking the API\nconst params = new URLSearchParams(window.location.search);\nconst code = params.get('code');\nconst state = params.get('state');\nif (!code || !state) {\n  const err = params.get('error_description') || params.get('error') || 'missing code/state';\n  showDeniedMessage(err); // user likely cancelled consent\n}","typeGuard":"function hasOAuthCallbackParams(q: Record<string, string | undefined>): q is Record<'code' | 'state', string> {\n  return typeof q.code === 'string' && q.code.length > 0 && typeof q.state === 'string' && q.state.length > 0;\n}","tryCatchPattern":"try {\n  await api.completeTikTokAuth(code, state);\n} catch (e) {\n  if ((e as any).status === 400 && /缺少必要的参数/.test((e as Error).message)) {\n    return restartTikTokOAuth();\n  }\n  throw e;\n}","preventionTips":["Handle TikTok's error redirect params (error=access_denied) explicitly instead of relying on code/state checks.","Never call the callback endpoint manually; always follow TikTok's redirect.","Register a clean redirect_uri without colliding query strings.","Show a user-facing retry button when callback params are missing."],"tags":["oauth","callback","validation","tiktok"],"backgroundTag":"oauth-callback-missing-code","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}