Webhooks can be observed to come from LinkMoney web and IP addresses, but sometimes this is not enough to to verify that the webhook's payload is secure. To work around this, LinkMoney uses a Webhook-Verification
header.
Note that the verification step is optional; LinkMoney webhooks can be used without the verification step.
<aside>
ℹ️ LinkMoney does not recommend building authentication yourself. For this walkthrough, we are using the express-jwt
package provided and maintained by Auth0.
</aside>
const jwt = require("express-jwt");
const { headers } = request;
const verificationHeader = request['Webhook-Verification'];
// yields JWT
const JWT = jwt.decode(verificationHeader);
{
"alg": "ES256",
"kid": "bfbd5111-8e33-4643-8ced-b2e642a72f3c",
"typ": "JWT"
}
alg
field is not ES256
, reject the webhook.kid
field to request a webhook verification key.const { kid } = JWT; // see step one for getting JWT
const response = await request("/webhook__verification_key", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: {
"client_id": {MY_CLIENT_ID},
"client_secret": {MY_CLIENT_SECRET),
"key_id": kid, // add the kid here.
},
});
if (response.ok) {
const data = await response.json();
const { key } = data;
return key;
} else {
// error
}
This call will yield a JSON payload containing a single property, key
. This key is a JWK.
{
"key": {
"alg": "ES256",
"created_at": 1560466150,
"crv": "P-256",
"expired_at": null,
"kid": "bfbd5111-8e33-4643-8ced-b2e642a72f3c",
"kty": "EC",
"use": "sig",
"x": "hKXLGIjWvCBv-cP5euCTxl8g9GLG9zHo_3pO5NN1DwQ",
"y": "shhexqPB7YffGn6fR6h2UhTSuCtPmfzQJ6ENVIoO4Ys"
},
"request_id": "RZ6Omi1bzzwDaLo"
}
If the request does not return a key, reject the webhook.
const client = new JwksClient(options)
const key; // see above for deriving the JWK
const jwtCheck = expressJwt({
secret: key,
// audience
// issuer
algorithms: ["ES256"],
});
module.exports = jwtCheck;
If the call's signature is invalid, it will be rejected by the middleware.
app.post("/my-api/webhook", jwtCheck, // my middlewares);