hooksig / PayPal
RSA-SHA256 · base64 · no timestamp
PayPal
Not HMAC at all. PayPal signs with RSA; you verify against their public certificate.
Try it — live, in your browser
Request — edit anything
Verify this in code
import { verify } from "hooksig";
const result = await verify("paypal", {
payload: rawBody,
headers: request.headers,
webhookId: env.PAYPAL_WEBHOOK_ID,
publicKey: cachedPayPalKey, // from paypal-cert-url
});
if (!result.verified) {
return new Response(result.reason, { status: 400 });
}no match — signature invalid
Signed string
RSA-SHA256 verify( publicKey, signed string, signature )
Signature
provided
Does not verify against the supplied public key.
How it's built
The scheme
- Header
paypal-transmission-sig - AlgorithmRSA-SHA256
- Encodingbase64
- Timestampnone — add your own if you need it
- SignsRSA (SHA256withRSA) over `{transmissionId}|{transmissionTime}|{webhookId}|crc32(body)`, verified with PayPal's public key.
Gotchas
- This is asymmetric. There is no shared secret; you verify an RSA signature with PayPal's public key.
- The signed string mixes headers, YOUR webhook id, and a CRC32 of the raw body, joined by pipes.
- You must fetch, validate, and cache the cert from paypal-cert-url yourself. hooksig verifies given the key; it never fetches remote certs.
- hooksig verifies PayPal in the SDK only; the playground below runs on the SDK path, not the WASM core.