Created
April 23, 2024 20:38
-
-
Save bmorrisondev/edcbb2996f99d6633846d3223863e41c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { WebhookEvent } from "@clerk/nextjs/server"; | |
import { headers } from "next/headers"; | |
import { NextRequest, NextResponse } from "next/server"; | |
import { Webhook } from "svix" | |
type WebhooksHandler = { | |
config: WebhookRegistrationConfig | |
POST: (req: NextRequest) => Promise<NextResponse | Response> | |
} | |
export function createWebhooksHandler(config: WebhookRegistrationConfig): WebhooksHandler { | |
return { | |
config: config, | |
POST: async (req: NextRequest) => await handleWebhooks(config, req) | |
} | |
} | |
export type WebhookRegistrationConfig = { | |
secret?: string | |
urlPrefix?: string | |
onUserCreated?: (event: WebhookEvent) => Promise<void | NextResponse>; | |
onUserUpdated?: (event: WebhookEvent) => Promise<void | NextResponse>; | |
} | |
export async function handleWebhooks(config: WebhookRegistrationConfig, req: NextRequest): Promise<NextResponse | Response> { | |
// If the request is not a POST request or does not start with the webhook URL, return a 404 | |
const WEBHOOK_SECRET = config.secret ? config.secret : process.env.WEBHOOK_SECRET | |
if (!WEBHOOK_SECRET) { | |
throw new Error('Please add WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local') | |
} | |
const headerPayload = headers(); | |
const svix_id = headerPayload.get("svix-id"); | |
const svix_timestamp = headerPayload.get("svix-timestamp"); | |
const svix_signature = headerPayload.get("svix-signature"); | |
if (!svix_id || !svix_timestamp || !svix_signature) { | |
return new Response('Error occurred -- no svix headers', { | |
status: 400 | |
}) | |
} | |
// Get the body | |
const payload = await req.json() | |
const body = JSON.stringify(payload); | |
const wh = new Webhook(WEBHOOK_SECRET); | |
let evt: WebhookEvent | |
try { | |
evt = wh.verify(body, { | |
"svix-id": svix_id, | |
"svix-timestamp": svix_timestamp, | |
"svix-signature": svix_signature, | |
}) as WebhookEvent | |
} catch (err) { | |
console.error('Error verifying webhook:', err); | |
return new Response('Error occured', { | |
status: 400 | |
}) | |
} | |
switch(evt.type) { | |
case 'user.created': | |
if (config.onUserCreated) { | |
return await _handler(evt, config.onUserCreated) | |
} | |
break; | |
case 'user.updated': | |
if (config.onUserUpdated) { | |
return await _handler(evt, config.onUserUpdated) | |
} | |
break; | |
} | |
// If we don't have a handler for the event, return a 404 | |
return NextResponse.next() | |
} | |
async function _handler(event: WebhookEvent, callback: Function): Promise<NextResponse | Response> { | |
let response = await callback(event) | |
if(response != undefined) { | |
return response | |
} else { | |
return new Response('', { status: 200 }) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment