Payload Signature
Saleor calculates a payload signature and puts the result into Saleor-Signature header:
- DEPRECATED if secretKeywas set for a webhook - the HMAC SHA-256 header based on it and the payload
- if secretKeywasn'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
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 â–¼