Error message: "An unauthorized signature detected during LemonSqueezy Webhooks integration"

When a payment is successfully made using the LemonSqueezy API, a webhook sends a payload. However, I am encountering an issue with verifying the signature. For more information, you can refer to this documentation:

Below is my TypeScript code for a post request:

import express, { Request, Response } from 'express';
import * as crypto from 'crypto';
import bodyParser from 'body-parser';

const webhook = express.Router();
let secret = "secretkey"

webhook.use(bodyParser.json())

webhook.post('/webhooks', async (req: Request, res: Response) => {
    try {
        if (!req.body) {
            throw new Error('Missing request body');
        }

        // Create HMAC signature
        const hmac = crypto.createHmac('sha256', secret);
        const digest = Buffer.from(hmac.update(JSON.stringify(req.body)).digest('hex'), 'utf8');

        // Retrieve and validate X-Signature header
        const signature = Buffer.from(req.get('X-Signature') || '', 'utf8');
        if (!crypto.timingSafeEqual(digest, signature)) {
            throw new Error('Invalid signature');
        }

        const payload = req.body;

        console.log('Received valid webhook:', payload);

        return res.status(200).send({'Webhook received': payload});
    } catch (err) {
        console.error(err);
        return res.status(400).send(err); 
    }
});

export default webhook

Answer №1

After spending countless hours on this, I finally figured out the root of the issue - the request was in string format instead of the raw body.

The solution? Simply download npm i raw-body.

    interface Request extends ExpressRequest {
    rawBody?: string;
}

const webhook = express.Router();
let secret = ""

webhook.use((req: Request, _res: Response, next: NextFunction) => {
    rawBody(req, {
        length: req.headers['content-length'],
        limit: '1mb', // Set your desired limit here
        encoding: 'utf8' // or any encoding you prefer
    }, (err, string) => {
        if (err) return next(err);
        (req as any).rawBody = string; // Define rawBody property on Request type
        next();
    });
});

webhook.post('/webhooks', async (req: Request, res: Response) => {
    try {
        if (!req.rawBody) {
            throw new Error('Missing request body');
        }

        // Create HMAC signature
        const hmac = crypto.createHmac('sha256', secret);
        const digest = Buffer.from(hmac.update(req.rawBody).digest('hex'), 'utf8');
        const signature = Buffer.from(req.get('X-Signature') || '', 'utf8');

        if (!crypto.timingSafeEqual(digest, signature)) {
            throw new Error('Invalid signature.');
        }

        const data = JSON.parse(req.rawBody)
        console.log(data)

        return res.status(200).send('Webhook received');
    } catch (err) {
        console.error(err);
        return res.status(400).send(err);
    }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A Step-by-Step Guide to Presenting Unstructured Data in HTML using Node.js and MongoDB

Currently, I am utilizing mongodb to store error logs of my application as json documents. My goal is to present these error logs in HTML format instead of just displaying the raw json content directly on the browser. The structure of the logs is schemales ...

Interacting with the Dropdown feature on the page causes the body of the page to shift

I am encountering an issue with 2 dropdowns in Datatables used to filter content. The problem arises when a dropdown is positioned on the right side of the page, causing a shift to the left by approximately 10px. Conversely, if the dropdown is placed on th ...

How do I implement the functionality to enable a user to download a file from a link using the Express framework?

I have a function that lets you make a new folder in the server's directory, and then upload files there. I'm attempting to view them using a direct link, such as this one: http://localhost:5000/attachments/1618413024408--1.jpg Even though the ...

What is the reason for TS expressing dissatisfaction about the use of a type instead of a type entry being provided

Below is a snippet of code for a Vue3 component that takes in an Array of Objects as a prop: <script lang="ts"> interface CorveesI { What: string, Who: string, Debit: number } export default { name: 'Corvees', props: { ...

The functionality of Everyauth seems to be malfunctioning in the latest version of Express

Currently, I am utilizing nodejs, express 4, and everyauth for social network authentication. I have encountered an issue where upon clicking Accept from Google and getting redirected back to my /, an error message appears: _http_outgoing.js:335 throw ne ...

Retrieving the output from a nested scope within a function

I have a scenario where I am working with a function that has a nested "then" function containing a return statement. My goal is to combine this inner return data with the outer return data. Below is the code snippet: public async getAllWidgets(): Promis ...

Learn how to acquire a JWT token with Next Auth V5

I am struggling to understand how Next Auth creates a JWT token, and I'm unsure of how to retrieve it. Here is the configuration within the auth.ts file: import NextAuth from "next-auth"; import Google from "next-auth/providers/google& ...

How do I correctly specify the parameter type of a function when passing a React functional component as an argument in TypeScript?

I am facing an issue with type declaration for function parameters. See the code snippet below, const FunctionalComponent = ({propA,propB}: FunctionalComponentProps): JSX.Element => { return } Now, I need to pass the FunctionalComponent as a parame ...

Axios and Express are throwing an error of "response is not defined

I'm facing an issue with the post method in my back-end code. Here's a simplified version of it: router.post('/users', async function(request, response) { try { const userToRegister = request.body; const user = await CreateUse ...

Using NodeJS to retrieve data automatically upon server initialization

Exploring the world of Node and asynchronous programming, I am currently working on a website where data from external websites needs to be fetched and displayed to the client (AngularJS Client). My goal is to have the server fetch data from these extern ...

Absolute imports in create-react-app do not function properly when using yarn v2 workspaces alongside typescript

I am currently utilizing yarn v2 workspaces, and within my workspaces, I have a frontend project built using create-react-app / react-scripts. My goal is to enable absolute imports in the frontend application so that I can simply do things like import Butt ...

What are some strategies to improve the SEO-friendliness of my URL by eliminating special characters like

I am working with ejs, expressjs, and mongoose to render templates using ejs. On one of my landing pages, the title is included in the URL. The title input by the user may contain spaces or not. If spaces are entered, the URL looks like this: http://loca ...

Issues arise when trying to update the modelValue in unit tests for Vue3 Composition API

Recently delving into Vue, I am currently engaged in writing unit tests for a search component incorporated in my project. Basically, when the user inputs text in the search field, a small X icon emerges on the right side of the input box. Clicking this X ...

Building New Web Pages with Express in Node.JS

I want to dynamically generate a new page on Node.JS with Express upon user form submission. Here is my initial approach, but it's not working as expected: var app = require('express')(); var server= require('http').createServer(a ...

Managing state on the login page functions properly, although there is a minor inconvenience of having to click the login button twice after entering the username and password

In Login.tsx, I store user/pass info in a useState called login and pass it up to App.tsx. I then store the access property from login useState to access useState inside App.tsx. While this does technically work, there is an issue where it seems to be one ...

Leverage Express JS to prevent unauthorized requests from the Client Side

Exploring the functionalities of the Express router: const express = require("express"); const router = express.Router(); const DUMMY_PLACES = [ { id: "p1", title: "Empire State Building", description: "One of the most famous sky scrapers i ...

Ways to retrieve dictionary keys as an array in Angular

Here is an example of an Angular dictionary: { ARRAY1: [{...}, {...}, {...}] ARRAY2: [{...}, {...}, {...}] ARRAY3: [{...}, {...}] ARRAY4: [{...}] } I want to show all the keys of arrays from this dictionary on an HTML page. I attempted to do ...

The specified format of `x-access-token` does not match the required type `AxiosRequestHeaders | undefined`

I am encountering an issue while trying to add an authHeader to the "Service". The error message displayed is: Type '{ 'x-access-token': any; } | { 'x-access-token'?: undefined; }' is not assignable to type 'AxiosRequest ...

Having trouble with vscode compiling the typescript file?

Even though I diligently followed the tutorial provided by vscode on compiling typescript code, I encountered a problem. The configurations were set up as per the instructions in the tutorial, but when I tried to run the code without debugging, I received ...

Using Ionic to send email verification via Firebase

I have encountered an issue while attempting to send an email verification to users upon signing up. Even though the user is successfully added to Firebase, the email verification is not being sent out. Upon checking the console for errors, I found the f ...