Last active
November 15, 2023 15:04
-
-
Save Xennis/1fec5a6fed1023c9eedee21c7ff27c2f to your computer and use it in GitHub Desktop.
Verify Paddle webhook signature as described in https://developer.paddle.com/webhooks/signature-verification (in TypeScript)
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 { createHmac } from "crypto" | |
// Verify according to https://developer.paddle.com/webhooks/signature-verification | |
const verifyPaddleSignature = async (payload: string, header: string | null, secret: string) => { | |
if (!header) { | |
return false | |
} | |
const [tsPart, h1Part] = header.split(";") | |
if (!tsPart || !h1Part) { | |
return false | |
} | |
const [_tsName, ts] = tsPart.split("=") | |
const [_h1Name, h1] = h1Part.split("=") | |
if (!ts || !h1) { | |
return false | |
} | |
const hmac = createHmac("sha256", secret).update(`${ts}:${payload}`).digest("hex").toString() | |
return hmac === h1 | |
} | |
// Example usage: | |
export async function POST(request: Request) { | |
const payload = await request.text() | |
const valid = await verifyPaddleSignature( | |
payload, | |
request.headers.get("Paddle-Signature"), | |
process.env.PADDLE_WEBHOOK_SECRET_KEY!, | |
) | |
if (!valid) { | |
return Response.json({ error: "unauthorized" }, { status: 401 }) | |
} | |
try { | |
const event = JSON.parse(payload) | |
console.log(event) | |
return Response.json({ message: "ok" }, { status: 200 }) | |
} catch (e) { | |
return Response.json({ error: "bad request" }, { status: 400 }) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment