{"record":{"id":"e410e7ca755626d0","repo":"yikart/AiToEarn","slug":"channelauthcodemissing","errorCode":"ChannelAuthCodeMissing","errorMessage":"ResponseCode.ChannelAuthCodeMissing","messagePattern":"ResponseCode\\.ChannelAuthCodeMissing","errorType":"exception","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-auth.provider.ts","lineNumber":241,"sourceCode":"      state: input.query?.state ?? input.body?.state,\n      token: input.query?.token ?? input.body?.token,\n      nickname: input.query?.nickname ?? input.body?.nickname,\n      avatar: input.query?.avatar ?? input.body?.avatar,\n      tickets: input.body?.tickets,\n    }\n    if (payload.token === undefined && payload.tickets === undefined) {\n      return undefined\n    }\n\n    const result = DouyinMiniAppCallbackSchema.safeParse(payload)\n    if (!result.success) {\n      const hasInvalidState = result.error.issues.some(issue => issue.path[0] === 'state')\n      const hasInvalidToken = result.error.issues.some(issue => issue.path[0] === 'token')\n      if (hasInvalidState) {\n        throw new AppException(ResponseCode.ChannelAuthCsrfInvalid)\n      }\n      if (hasInvalidToken) {\n        throw new AppException(ResponseCode.ChannelAuthCodeMissing)\n      }\n\n      throw new AppException(ResponseCode.ChannelAuthorizationFailed)\n    }\n\n    assertParsedCallbackState(result.data.state, input.session.id)\n    return result.data\n  }\n\n  private hasMiniAppScope(scopes: string | undefined, scope: string) {\n    return !!scopes?.split(/[,\\s]+/).includes(scope)\n  }\n\n  private maskOpenId(openId: string) {\n    if (openId.length <= 8) {\n      return openId\n    }\n","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-auth.provider.ts#L223-L259","documentation":"Thrown in parseMiniAppCallback when the callback payload fails schema validation on the 'token' field, i.e. the authorization code/token from Douyin is absent or invalid. Distinct from CSRF failure: the session state is fine but there is no usable auth token to exchange.","triggerScenarios":"Douyin mini-app callback where 'token' (the auth code field) is missing, empty, or of the wrong type per DouyinMiniAppCallbackSchema.","commonSituations":"User landed on the callback page without completing authorization, Douyin returned an error code instead of a token, frontend dropped the token query parameter, or the callback URL was visited directly.","solutions":["Have the user restart the mini-app authorization so Douyin issues a fresh token","Inspect the raw callback payload to confirm the token parameter name/value matches the schema","Check the frontend callback handler isn't stripping or renaming the token param before calling the backend"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const token = callbackPayload?.token\nif (typeof token !== 'string' || token.length === 0) {\n  throw new Error('Authorization callback is missing the token/code parameter')\n}","typeGuard":"function hasAuthCode(payload: unknown): payload is { token: string } {\n  return typeof payload === 'object' && payload !== null && typeof (payload as any).token === 'string' && (payload as any).token.length > 0\n}","tryCatchPattern":"try {\n  await provider.miniAppCallback(payload)\n} catch (e) {\n  if (e instanceof AppException && e.code === 'ChannelAuthCodeMissing') {\n    return { restartAuth: true, message: 'No authorization token received; please authorize again' }\n  }\n  throw e\n}","preventionTips":["Check for Douyin error codes in the callback before forwarding (user-cancelled auth yields no token)","Never reuse or cache callback URLs that contain a consumed token","Keep frontend param forwarding aligned with the backend schema field names"],"tags":["oauth","douyin","missing-parameter","validation"],"backgroundTag":"oauth-code-missing","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}