Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webhook signature problems with Nextjs #127

Open
achadee opened this issue Aug 5, 2024 · 1 comment
Open

Webhook signature problems with Nextjs #127

achadee opened this issue Aug 5, 2024 · 1 comment

Comments

@achadee
Copy link

achadee commented Aug 5, 2024

Hey guys, I can't seem to get the webhook verification working.

The docs seem to be out of date and the variables as I needed to manually construct the headers, currently getting "Signatures not match."

  const signature = headers().get("Messagebird-Signature");
  const timestamp = headers().get("Messagebird-Request-Timestamp");
  const body = await req.text();

  const result = validate(
    {
      headers: {
        "messagebird-request-timestamp": timestamp,
        "messagebird-signature": signature,
      },
      body,
      query: {
        statusDatetime: "2019-01-11T09:17:11+00:00",
      },
      url: `https://${process.env.NGROK_DEVELOPER_URL || process.env.NEXT_PUBLIC_WEB_URL}/api/webhooks/bird`,
    },
    process.env.BIRD_SHARED_SECRET || ""
  )
@achadee
Copy link
Author

achadee commented Aug 30, 2024

Attaching more code here, to be clear, still need help - Can someone from the technical team please reach out!

following these docs:
https://docs.bird.com/api/notifications-api/api-reference/webhooks/verifying-a-webhook

import { NextApiRequest, NextApiResponse } from 'next';
import crypto from 'crypto';
import { NextRequest } from 'next/server';
import { type IncomingHttpHeaders } from "http2";
import { headers } from 'next/headers'

export async function POST(
  req: NextRequest & {
    headers: IncomingHttpHeaders & {
      "Messagebird-Request-Timestamp": string;
      "Messagebird-Signature": string;
    };
  },
) {

  const headersList = headers()

  const signature = headersList.get('messagebird-signature')
  const timestamp = headersList.get('messagebird-request-timestamp')

  if (!signature || !timestamp) {
    return new Response(JSON.stringify({ message: 'Missing required headers' }), { status: 400 });
  }

  const body = await req.text();
  const url = req.url

  if (!verifyWebhook(signature, timestamp, body, url)) {
    return new Response(JSON.stringify({ message: 'Invalid signature' }), { status: 401 });
  }

  // Webhook is verified, process the payload
  const payload = JSON.parse(body.toString());
  console.log('Verified webhook payload:', payload);

  // Your webhook handling logic here

  return new Response(JSON.stringify({ message: 'Webhook received and verified' }), { status: 200 });
}

function verifyWebhook(signature: string, timestamp: string, body: string, url: string): boolean {

  // Base64 decode the messagebird-signature header return string;
  const decodedSignature = Buffer.from(signature, 'base64').toString('utf-8');

  // Create a SHA256 hash checksum of the request body as a binary result;
  const hash = crypto.createHash('sha256');
  const checksumBody = hash.update(body).digest("binary");

  const payload = [timestamp, url, checksumBody].join('\n')

  // Calculate HMACSHA256 using the signing key as the secret and the joined payload as the message;
  const hmac = crypto.createHmac('sha256', process.env.BIRD_SHARED_SECRET || "");
  const checksum = hmac.update(payload).digest('base64');

  // Compare the calculated checksum with the decoded signature;
  return checksum === decodedSignature;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant