yikart/AiToEarn · warning
-1
-1
Error message
ChannelWebhookInvalidSignature
What it means
The Douyin webhook provider rejects incoming webhook requests whose verify(request) check fails, responding 401 with code -1 and message ChannelWebhookInvalidSignature. The Douyin-signed payload did not match the configured secret, so the body is never parsed and no publish state is updated.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-webhook.provider.ts:25
import { PublishRecordRepository } from '@yikart/mongodb'
import { PublishStateService } from '../../publish/tasks/publish-state.service'
import { DouyinConfig } from './douyin.config'
import { buildDouyinVideoWorkLink, DouyinWebhookBodySchema, DouyinWebhookEvent } from './douyin.interface'
@Injectable()
export class DouyinWebhookProvider implements PlatformWebhookHandler {
private readonly logger = new Logger(DouyinWebhookProvider.name)
constructor(
private readonly config: DouyinConfig,
@Optional() private readonly publishRecordRepo?: PublishRecordRepository,
@Optional() private readonly stateService?: PublishStateService,
) {}
async handle(request: Request, response: Response): Promise<void> {
if (!this.verify(request)) {
this.logger.warn({ platform: AccountType.Douyin }, 'Douyin webhook signature invalid')
response.status(401).json({ code: -1, message: getCodeMessage(ResponseCode.ChannelWebhookInvalidSignature, undefined, getLocale()) })
return
}
const body = this.parseWebhookBody(request.body)
if (!body) {
response.status(200).json({ code: 0, message: 'ok' })
return
}
if (body.event === DouyinWebhookEvent.VerifyWebhook) {
response.status(200).json({ challenge: body.content.challenge })
return
}
if (body.event === DouyinWebhookEvent.CreateVideo) {
await this.applyCreateVideoResult(body)
response.status(200).json({ code: 0, message: 'ok' })
returnView on GitHub (pinned to d3aa8bea5b)
Solutions
- Verify the server's Douyin webhook secret matches the one configured in the Douyin open platform
- Ensure the raw request body is passed unchanged through any reverse proxy to the handler
- Confirm the request is hitting the correct environment deployment (cn vs intl secrets)
- Rotate and re-register the webhook secret on both sides if compromised or drifted
Example fix
// before
if (!this.verify(request)) {
this.logger.warn({ platform: AccountType.Douyin }, 'Douyin webhook signature invalid')
// after
if (!this.verify(request)) {
this.logger.warn({ platform: AccountType.Douyin, headers: request.headers['x-signature'] ? 'present' : 'missing' }, 'Douyin webhook signature invalid') Defensive patterns
Strategy: validation
Validate before calling
const expected = crypto.createHmac('sha256', douyinSecret).update(rawBody).digest('hex')
if (req.headers['x-signature'] !== expected) return res.status(401).json({ code: -1 }) Type guard
function isDouyinSigned(req: Request, secret: string): boolean {
const sig = req.headers['x-signature'] as string | undefined
return !!sig && crypto.timingSafeEqual(Buffer.from(sig), crypto.createHmac('sha256', secret).update((req.body as Buffer)).digest())
} Try / catch
app.post('/webhooks/douyin', express.raw({ type: 'application/json' }), (req, res) => {
if (!isDouyinSigned(req, process.env.DOUYIN_WEBHOOK_SECRET!)) {
return res.status(401).json({ code: -1, message: 'ChannelWebhookInvalidSignature' })
}
// parse and process payload
}) Prevention
- Keep the Douyin open-platform secret and server env in sync; rotate together
- Use express.raw for the webhook route so the signed bytes are verified exactly
- Deploy per-environment secrets and confirm the callback URL points at the right deployment
- Monitor 401 rates on the webhook endpoint as an alert signal
When it happens
Trigger: POST to the Douyin webhook endpoint with a missing/incorrect signature header, a secret mismatch between Douyin's app config and the server env, or the body altered in transit before verification.
Common situations: Secret rotated in Douyin open-platform console without updating server config; gateway/proxy recompressing or re-encoding the payload; wrong environment deployment receiving the callback; attackers probing the endpoint.
Related errors
- -1
- ChannelWebhookInvalidSignature
- ChannelWebhookInvalidSignature
- ChannelWebhookInvalidSignature
- invalid_signature
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/0f9982027f6efdec.
Report an issue: GitHub.