Payload Signature
Saleor calculates a payload signature and puts the result into Saleor-Signature
header:
- DEPRECATED if
secretKey
was set for a webhook - the HMAC SHA-256 header based on it and the payload - if
secretKey
wasn't set for a webhook - the JWS signature using RS256 with payload detached, to verify the signature you can use a public key, which can be fetched fromhttp(s)://<your-backend-domain>/.well-known/jwks.json
(available since Saleor 3.5, before 3.5 the payload from webhooks withoutsecretKey
set were not signed)
Validating signature
To validate signatures in Saleor Apps, use withWebhookSignatureVerified
middleware provided by @saleor/app-sdk
import type { Handler } from "retes";
import { Response } from "retes/response";
import { toNextHandler } from "retes/adapter";
import {
withSaleorEventMatch,
withWebhookSignatureVerified,
} from "@saleor/app-sdk/middleware";
const handler: Handler = async (request) => {
// ...
return Response.OK({ success: true });
};
export default toNextHandler([
withSaleorDomainMatch,
withWebhookSignatureVerified(),
handler,
]);
Expand ▼
You can also manually validate the JWS signature in JavaScript with the jose
package. Remember that you need to supply it with a raw body string, not a parsed object.
import getRawBody from "raw-body";
const JWKS = jose.createRemoteJWKSet(
new URL("https://master.staging.saleor.cloud" + "/.well-known/jwks.json")
);
// In Next.js you need to disable `bodyParser` in order to get raw body string
// https://github.com/vercel/next.js/discussions/12517
export const config = {
api: {
bodyParser: false,
},
};
export default function(req, res) {
const jws = req.headers["saleor-signature"];
const buffer = getRawBody(req, {
length: req.headers["content-length"],
limit: "1mb",
});
const [header, _, signature] = jws.split(".");
try {
await jose.flattenedVerify({
protected: header,
payload: buffer.toString("utf-8"),
signature
}, JWKS);
} catch (e) {
// return error
}
// handle your request
}
Expand ▼