yikart/AiToEarn · error
invalid_signature
Error message
invalid_signature
What it means
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.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/tiktok/tiktok-webhook.provider.ts:56
@Injectable()
export class TikTokWebhookProvider implements PlatformWebhookHandler {
private readonly logger = new Logger(TikTokWebhookProvider.name)
constructor(
private readonly config: TiktokConfig,
@Optional() private readonly publishRecordRepo?: PublishRecordRepository,
@Optional() private readonly stateService?: PublishStateService,
) {}
async handle(request: Request, response: Response): Promise<void> {
if (request.method === 'GET') {
const query = request.query as TikTokWebhookChallengeQuery
response.status(query.challenge ? 200 : 404).send(query.challenge ?? '')
return
}
if (!this.verify(request)) {
this.logger.warn({ platform: AccountType.TikTok }, 'TikTok webhook signature invalid')
response.status(401).json({ status: 'invalid_signature' })
return
}
const body = this.parseTikTokBody(request)
if (!body) {
response.status(200).json({ status: 'ok' })
return
}
await this.applyTikTokPublishResult(body)
response.status(200).json({ status: 'ok' })
}
private verify(request: RawBodyRequest): boolean {
const rawBody = request.rawBody
const signatureHeader = this.getHeader(request, 'tiktok-signature')
?? this.getHeader(request, 'x-tiktok-signature')
?? this.getHeader(request, 'x-tt-signature')
if (!signatureHeader || !rawBody || !this.config.clientSecret) {
return falseView on GitHub (pinned to d3aa8bea5b)
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
Example fix
// before
app.use(express.json()) // consumes body, rawBody lost
// after
app.use(express.json({ verify: (req, _res, buf) => { (req as any).rawBody = buf } })) Defensive patterns
Strategy: validation
Validate before calling
const sig = req.headers['x-tiktok-signature'] ?? req.headers['signature']
if (!sig || !rawBody || !process.env.TIKTOK_CLIENT_SECRET) throw new Error('missing TikTok signature inputs')
const expected = createHmac('sha256', process.env.TIKTOK_CLIENT_SECRET).update(rawBody).digest('hex')
if (!timingSafeEqual(Buffer.from(expected), Buffer.from(String(sig)))) throw new Error('TikTok signature mismatch') Type guard
function hasTikTokSignature(sig: unknown): sig is string {
return typeof sig === 'string' && sig.length > 0
} Prevention
- Match TikTok app secret across environments
- Capture rawBody verbatim before parsing
- Re-test webhooks after any secret rotation
When it happens
Trigger: POST to the TikTok webhook endpoint with missing/invalid signature header, missing rawBody, or an unset/incorrect clientSecret used by verify().
Common situations: 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.
Related errors
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/5b4c1883741ca21b.
Report an issue: GitHub.