{"record":{"id":"b47183fc5b11ff8f","repo":"yikart/AiToEarn","slug":"channelwebhookinvalidverifytoken","errorCode":null,"errorMessage":"ChannelWebhookInvalidVerifyToken","messagePattern":"ChannelWebhookInvalidVerifyToken","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/facebook/facebook-webhook.provider.ts","lineNumber":66,"sourceCode":"    }\n    response.status(200).send('EVENT_RECEIVED')\n  }\n\n  private handleChallenge(request: Request, response: Response): void {\n    const {\n      'hub.mode': mode,\n      'hub.verify_token': verifyToken,\n      'hub.challenge': challenge,\n    } = request.query as FacebookWebhookChallengeQuery\n    if (\n      mode === 'subscribe'\n      && verifyToken === this.config.webhookVerifyToken\n      && challenge\n    ) {\n      response.status(200).send(challenge)\n      return\n    }\n    response.status(403).send(getCodeMessage(ResponseCode.ChannelWebhookInvalidVerifyToken, undefined, getLocale()))\n  }\n\n  private parseMetaBody(request: Request): FacebookWebhookBody {\n    const parsed = FacebookWebhookBodySchema.safeParse(request.body)\n    if (!parsed.success) {\n      this.logger.warn({ platform: AccountType.Facebook }, 'Facebook webhook body invalid')\n      return {}\n    }\n    return parsed.data\n  }\n\n  private async applyFacebookChange(change: FacebookWebhookChange): Promise<void> {\n    if (change.field !== FacebookWebhookField.Feed || change.value.comment_id) {\n      this.logger.log({ platform: AccountType.Facebook }, 'Facebook webhook event ignored')\n      return\n    }\n    if (!this.publishRecordRepo || !this.stateService) {\n      return","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/facebook/facebook-webhook.provider.ts#L48-L84","documentation":"Facebook webhook subscription verification (handleChallenge, called from handle for GET hub.mode=subscribe requests) responds 403 with ChannelWebhookInvalidVerifyToken when the hub.verify_token query parameter does not equal config.webhookVerifyToken or the challenge is missing. Meta sends this token once when you register the webhook URL; mismatch means Meta cannot complete subscription verification.","triggerScenarios":"Meta calls GET /webhooks/facebook?hub.mode=subscribe&hub.verify_token=...&hub.challenge=... while the verify_token differs from the server's configured webhookVerifyToken, or hub.challenge is absent.","commonSituations":"Verify token entered in the Meta App dashboard differs from the server env value; token rotated on one side only; deploying the wrong environment (cn vs intl config) that holds a different token; URL queried manually for testing with a wrong token.","solutions":["Copy the exact webhookVerifyToken from server config into the Meta App dashboard webhook verification field (or vice versa)","Redeploy/restart the server so the current env value is loaded, confirming the right environment is running","Re-attempt subscription in the Meta dashboard after aligning the token","Ensure hub.challenge is passed through; do not manually test without all three hub params"],"exampleFix":"// before\n// token hardcoded/drifted between dashboard and env\nconst WEBHOOK_VERIFY_TOKEN = 'old-token'\n// after\nconst WEBHOOK_VERIFY_TOKEN = process.env.FACEBOOK_WEBHOOK_VERIFY_TOKEN\nif (!WEBHOOK_VERIFY_TOKEN)\n  throw new Error('FACEBOOK_WEBHOOK_VERIFY_TOKEN is required')","handlingStrategy":"validation","validationCode":"if (req.query['hub.mode'] === 'subscribe' && req.query['hub.verify_token'] !== WEBHOOK_VERIFY_TOKEN)\n  return res.status(403).send('ChannelWebhookInvalidVerifyToken')","typeGuard":"function isChallengeValid(req: Request, token: string): boolean {\n  return req.query['hub.mode'] === 'subscribe'\n    && req.query['hub.verify_token'] === token\n    && typeof req.query['hub.challenge'] === 'string'\n    && req.query['hub.challenge'].length > 0\n}","tryCatchPattern":"app.get('/webhooks/facebook', (req, res) => {\n  if (isChallengeValid(req, process.env.FACEBOOK_WEBHOOK_VERIFY_TOKEN!)) {\n    return res.status(200).send(req.query['hub.challenge'])\n  }\n  res.status(403).send('ChannelWebhookInvalidVerifyToken')\n})","preventionTips":["Use the identical verify token string in the Meta dashboard and server env; rotate together","Confirm the deployed environment's token before subscribing the webhook in Meta","Return hub.challenge verbatim on success so Meta completes subscription","Test subscription immediately after any token or deployment change"],"tags":["webhook","verification","meta","config"],"backgroundTag":"webhook-verify-token-mismatch","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}