From e40ec66e5624f1dccde3064b10fd62d59245b895 Mon Sep 17 00:00:00 2001 From: Joseph J Helfenbein Date: Sat, 25 Jan 2025 03:17:02 -0500 Subject: [PATCH] fix handling of signing secret --- package.json | 1 + src/app/api/webhook/route.js | 54 +++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index fd9e4de..6babd0c 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "next-themes": "^0.4.4", "react": "^19.0.0", "react-dom": "^19.0.0", + "svix": "^1.45.1", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7" }, diff --git a/src/app/api/webhook/route.js b/src/app/api/webhook/route.js index c477993..8f96fcc 100644 --- a/src/app/api/webhook/route.js +++ b/src/app/api/webhook/route.js @@ -1,7 +1,7 @@ import mongoose from 'mongoose'; import { User } from '../../../models/User'; -import crypto from 'crypto'; import { NextResponse } from 'next/server'; +import { Webhook } from 'svix'; const CLERK_WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET; @@ -17,35 +17,37 @@ export async function POST(req) { console.log('Received request:', req); if (req.method !== 'POST') { - console.log('Method not allowed'); + console.log('Method not allowed'); return NextResponse.json( { message: 'Method Not Allowed' }, { status: 405 } ); } + const payload = await req.text(); + const headers = { + 'svix-id': req.headers.get('svix-id'), + 'svix-timestamp': req.headers.get('svix-timestamp'), + 'svix-signature': req.headers.get('svix-signature'), + }; + + const wh = new Webhook(CLERK_WEBHOOK_SECRET); + + let evt; try { - const webhookSignature = req.headers.get('clerk-signature'); - const payload = JSON.stringify(await req.json()); - console.log('Webhook Payload:', payload); - console.log('Received Clerk Signature:', webhookSignature); + evt = wh.verify(payload, headers); + } catch (err) { + console.log('Invalid webhook signature'); + return NextResponse.json( + { message: 'Invalid webhook signature' }, + { status: 400 } + ); + } - const hmac = crypto.createHmac('sha256', CLERK_WEBHOOK_SECRET); - hmac.update(payload); - const computedSignature = hmac.digest('hex'); - console.log('Computed Signature:', computedSignature); + const eventType = evt.type; - if (computedSignature !== webhookSignature) { - console.log('Invalid webhook signature'); - return NextResponse.json( - { message: 'Invalid webhook signature' }, - { status: 400 } - ); - } - - await connectDB(); - - const { first_name, last_name, email_addresses } = await req.json(); + if (eventType === 'user.created') { + const { first_name, last_name, email_addresses } = evt.data; const email = email_addresses && email_addresses[0] ? email_addresses[0].email_address : null; console.log('Clerk Data:', { first_name, last_name, email }); @@ -60,6 +62,8 @@ export async function POST(req) { ); } + await connectDB(); + let user = await User.findOne({ email }); if (user) { console.log('User already exists'); @@ -84,11 +88,11 @@ export async function POST(req) { { message: 'User successfully created' }, { status: 200 } ); - } catch (error) { - console.error('Error during webhook processing:', error); + } else { + console.log(`Unhandled event type: ${eventType}`); return NextResponse.json( - { message: 'Internal server error' }, - { status: 500 } + { message: `Unhandled event type: ${eventType}` }, + { status: 400 } ); } }