Clerk 和 Svix Web hook 无法正常工作,并出现错误:“src 属性必须是有效的 json 对象”

问题描述 投票:0回答:2

我正在尝试将我的 Clerk 数据同步到我的 Next js 13 项目中的数据库。我的 webhooks 通过 Ngrok 公开暴露。这是我的代码:

import { IncomingHttpHeaders } from "http";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { Webhook, WebhookRequiredHeaders } from "svix";

const webhookSecret = process.env.WEBHOOK_SECRET || "";

async function handler(request: Request) {

  console.log(await request.json())

  const payload = await request.json();
  const headersList = headers();
  const heads = {
    "svix-id": headersList.get("svix-id"),
    "svix-timestamp": headersList.get("svix-timestamp"),
    "svix-signature": headersList.get("svix-signature"),
  };
  const wh = new Webhook(webhookSecret);
  let evt: Event | null = null;

  try {
    evt = wh.verify(
      JSON.stringify(payload),
      heads as IncomingHttpHeaders & WebhookRequiredHeaders
    ) as Event;
  } catch (err) {
    console.error((err as Error).message);
    return NextResponse.json({}, { status: 400 });
  }

  const eventType: EventType = evt.type;
  if (eventType === "user.created" || eventType === "user.updated") {
    const { id, ...attributes } = evt.data;
    console.log(attributes)
  }
}

type EventType = "user.created" | "user.updated" | "*";

type Event = {
  data: Record<string, string | number>;
  object: "event";
  type: EventType;
};

export const GET = handler;
export const POST = handler;
export const PUT = handler;

此代码应执行以下操作:

  1. /api/webhooks/user
  2. 下创建API路由
  3. 获取有效负载和标头
  4. 通过 Svix 验证此信息
  5. 控制台信息

但是,据我所知,只有步骤 1 有效。在我的职员仪表板中,我收到错误:

{
  "message": "src property must be a valid json object"
}

编辑:

使用以下代码我仍然遇到相同的错误:

import { Webhook, WebhookRequiredHeaders } from "svix";

const webhookSecret = process.env.WEBHOOK_SECRET || "";

async function handler(request: Request) {
    const svix_id = request.headers.get("svix-id") ?? "";
    const svix_timestamp = request.headers.get("svix-timestamp") ?? "";
    const svix_signature = request.headers.get("svix-signature") ?? "";

    const body = await request.text(); // This get's the raw body as a string

    const sivx = new Webhook("your_secret_key_here");

    const payload = sivx.verify(body, {
        "svix-id": svix_id,
        "svix-timestamp": svix_timestamp,
        "svix-signature": svix_signature,
    });

    console.log(payload)
}

export const GET = handler;
export const POST = handler;
export const PUT = handler;

我哪里出错了?

next.js webhooks ngrok clerk
2个回答
5
投票

您需要将 webhook 端点添加到 middleware.ts 中的忽略路由中:

export default authMiddleware({
  publicRoutes: ['/'],
  ignoredRoutes: ['/api/{routeName}'],
});

然而,令人烦恼的是,很少有文档来强调这一点。


0
投票

对于使用 Hono 的人,我使用以下代码使其工作。

app.post('/', async (c) => {
    try {
        const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET
        if (!WEBHOOK_SECRET) {
            throw new Error('You need a WEBHOOK_SECRET in your .env')
        }
        const payload = await c.req.text()
        const svix_id = c.req.header('svix-id')
        const svix_timestamp = c.req.header('svix-timestamp')
        const svix_signature = c.req.header('svix-signature')

        // If there are no Svix headers, error out
        if (!svix_id || !svix_timestamp || !svix_signature) {
            console.error('Issue in headers of webhook')
            return c.text('Error occurred -- no svix headers', {
                status: 400,
            })
        }

        // Create a new Svix instance with your secret.
        const wh = new Webhook(WEBHOOK_SECRET)

        let evt = null

        // Attempt to verify the incoming webhook
        // If successful, the payload will be available from 'evt'
        // If the verification fails, error out and  return error code
        try {
            evt = wh.verify(payload, {
                'svix-id': svix_id,
                'svix-timestamp': svix_timestamp,
                'svix-signature': svix_signature,
            }) as { data: OrganizationMembershipJSON; type: string }
            console.log('evt type: ', evt.type)
            console.log('evt data: ', evt.data?.id)
        } catch (err) {
            if (err instanceof Error) {
                console.error('Error verifying webhook:', err.message)
                return c.text(err.message, 400)
            }
            return c.text('Something went wrong', 500)
        }

        return c.text('Webhook received and verified successfully', 200)
    } catch (e) {
        if (e instanceof Error) {
            return c.json(e.message, 400)
        }
        return c.text('Something went wrong', 500)
    }
})
© www.soinside.com 2019 - 2024. All rights reserved.