Skip to content

Instantly share code, notes, and snippets.

@Xennis
Last active November 15, 2023 15:04
Show Gist options
  • Save Xennis/1fec5a6fed1023c9eedee21c7ff27c2f to your computer and use it in GitHub Desktop.
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)
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