-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
verify webhook signature #59
Comments
Implemented signature verification for my Next.js project by wrapping the webhooks in another function. Here's the code for reference: const webhooks = createNextWebhooks({
secrets: {
sanity: {
projectId: NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: NEXT_PUBLIC_SANITY_DATASET,
authToken: SANITY_READ_WRITE_AUTH_TOKEN,
},
shopify: {
shopName: NEXT_PUBLIC_SHOPIFY_SHOP_ID,
accessToken: NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN,
},
},
});
function verifyShopifyWebhook(
func: (request: NextApiRequest, response: NextApiResponse) => void,
) {
return async (request: NextApiRequest, response: NextApiResponse) => {
if (!SHOPIFY_WEBHOOK_SHARED_SECRET) {
console.error(
'Missing environment variable SHOPIFY_WEBHOOK_SHARED_SECRET',
);
// Still sending 200 to avoid Shopify disabling our hook
return response.status(200).end();
}
const hmac =
request.headers['x-shopify-hmac-sha256'] ||
request.headers['X-Shopify-Hmac-Sha256'];
const body = await rawBody(request);
// Create a hash using the body and our key
const hash = crypto
.createHmac('sha256', SHOPIFY_WEBHOOK_SHARED_SECRET)
.update(body)
.digest('base64');
if (hash === hmac) {
// Sane Shopify expects a parsed body
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
request.body = JSON.parse(body.toString('utf8'));
return func(request, response);
}
console.error('Mismatched Shopify webhook signature');
// Still sending 200 to avoid Shopify disabling our hook
return response.status(200).end();
};
}
const onProductUpdate = verifyShopifyWebhook(webhooks.onProductUpdate);
const onProductDelete = verifyShopifyWebhook(webhooks.onProductDelete);
const onCollectionUpdate = verifyShopifyWebhook(webhooks.onCollectionUpdate);
const onCollectionDelete = verifyShopifyWebhook(webhooks.onCollectionDelete);
export {
onProductUpdate,
onProductDelete,
onCollectionDelete,
onCollectionUpdate,
}; In Useimport { onProductUpdate } from '../../utils/webhooks';
// We need the raw body to construct a valid signature comparison
export const config = { api: { bodyParser: false } };
export default onProductUpdate; Bonus TypeScript Typesdeclare module '@sane-shopify/server' {
import type { NextApiRequest, NextApiResponse } from 'next';
interface CreateNextWebhooksConfig {
secrets: {
sanity: {
projectId: string;
dataset: string;
authToken: string;
};
shopify: {
shopName: string;
accessToken: string;
};
};
onError?: (error: Error) => void;
}
interface Webhooks {
onCollectionUpdate: (
request: NextApiRequest,
response: NextApiResponse,
) => void;
onCollectionDelete: (
request: NextApiRequest,
response: NextApiResponse,
) => void;
onProductUpdate: (
request: NextApiRequest,
response: NextApiResponse,
) => void;
onProductDelete: (
request: NextApiRequest,
response: NextApiResponse,
) => void;
onOrderCreate: (request: NextApiRequest, response: NextApiResponse) => void;
}
export function createNextWebhooks(
config: CreateNextWebhooksConfig,
): Webhooks;
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No description provided.
The text was updated successfully, but these errors were encountered: