{"record":{"id":"5b4c1883741ca21b","repo":"yikart/AiToEarn","slug":"invalid-signature","errorCode":null,"errorMessage":"invalid_signature","messagePattern":"invalid_signature","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/tiktok/tiktok-webhook.provider.ts","lineNumber":56,"sourceCode":"@Injectable()\nexport class TikTokWebhookProvider implements PlatformWebhookHandler {\n  private readonly logger = new Logger(TikTokWebhookProvider.name)\n\n  constructor(\n    private readonly config: TiktokConfig,\n    @Optional() private readonly publishRecordRepo?: PublishRecordRepository,\n    @Optional() private readonly stateService?: PublishStateService,\n  ) {}\n\n  async handle(request: Request, response: Response): Promise<void> {\n    if (request.method === 'GET') {\n      const query = request.query as TikTokWebhookChallengeQuery\n      response.status(query.challenge ? 200 : 404).send(query.challenge ?? '')\n      return\n    }\n    if (!this.verify(request)) {\n      this.logger.warn({ platform: AccountType.TikTok }, 'TikTok webhook signature invalid')\n      response.status(401).json({ status: 'invalid_signature' })\n      return\n    }\n    const body = this.parseTikTokBody(request)\n    if (!body) {\n      response.status(200).json({ status: 'ok' })\n      return\n    }\n    await this.applyTikTokPublishResult(body)\n    response.status(200).json({ status: 'ok' })\n  }\n\n  private verify(request: RawBodyRequest): boolean {\n    const rawBody = request.rawBody\n    const signatureHeader = this.getHeader(request, 'tiktok-signature')\n      ?? this.getHeader(request, 'x-tiktok-signature')\n      ?? this.getHeader(request, 'x-tt-signature')\n    if (!signatureHeader || !rawBody || !this.config.clientSecret) {\n      return false","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/tiktok/tiktok-webhook.provider.ts#L38-L74","documentation":"TikTok webhook provider returns a plain JSON 401 { status: 'invalid_signature' } when the request's signature header fails HMAC verification against the configured secret. The event is discarded rather than processed.","triggerScenarios":"POST to the TikTok webhook endpoint with missing/invalid signature header, missing rawBody, or an unset/incorrect clientSecret used by verify().","commonSituations":"TikTok app secret changed or misconfigured in env; payload proxied through a service that re-encodes the body; encrypted payloads signed with a different key than configured; scanners posting unsigned junk to the public URL.","solutions":["Confirm the configured TikTok client secret matches the app that sends the webhooks","Ensure rawBody is captured verbatim (no re-serialization) before verification","Check any intermediary services preserve headers and body bytes","Rotate/re-register the webhook in the TikTok developer console after secret changes"],"exampleFix":"// before\napp.use(express.json()) // consumes body, rawBody lost\n// after\napp.use(express.json({ verify: (req, _res, buf) => { (req as any).rawBody = buf } }))","handlingStrategy":"validation","validationCode":"const sig = req.headers['x-tiktok-signature'] ?? req.headers['signature']\nif (!sig || !rawBody || !process.env.TIKTOK_CLIENT_SECRET) throw new Error('missing TikTok signature inputs')\nconst expected = createHmac('sha256', process.env.TIKTOK_CLIENT_SECRET).update(rawBody).digest('hex')\nif (!timingSafeEqual(Buffer.from(expected), Buffer.from(String(sig)))) throw new Error('TikTok signature mismatch')","typeGuard":"function hasTikTokSignature(sig: unknown): sig is string {\n  return typeof sig === 'string' && sig.length > 0\n}","tryCatchPattern":null,"preventionTips":["Match TikTok app secret across environments","Capture rawBody verbatim before parsing","Re-test webhooks after any secret rotation"],"tags":["webhook","signature","tiktok","security"],"backgroundTag":"webhook-signature-verification-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}