Hi there,
I am looking to create a simple fetch request using Cloudflare Workers as a proxy url.
This is working to a point, however when trying to use the https://github.com/Shopify/shopify-app-js to validate the hmac, it’s not succeeding.
I have tried an alternative solution manually validating the hmac and this does work https://github.com/Shopify/shopify-api-js/issues/878#issue-1713165039
Here is my code to hopefully give an idea on what i’m doing and whether it’s wrong - it always returns ‘Not valid’:
import { shopifyApi, ApiVersion } from '@shopify/shopify-api';
import '@shopify/shopify-api/adapters/cf-worker';
import { AutoRouter, json } from 'itty-router';
const router = AutoRouter();
router.all('*', async ({ query }) => {
const hmac = query.signature;
const shopify = shopifyApi({
apiSecretKey: 'Client_ID', // Removed for example
adminApiAccessToken: 'Client_Secret', // Removed for example
apiVersion: ApiVersion.April24,
isCustomStoreApp: true,
isEmbeddedApp: false,
hostName: 'example.myshopify.com', // Removed for example
});
const isValid = await shopify.utils.validateHmac(query, {
signator: 'appProxy'
});
if (isValid) {
return 'Valid';
} else {
return 'Not valid';
}
});
export default { ...router };
I have tried this alternative solution without the use of the noded module and it does validate successfully and returns true:
import crypto from 'node:crypto';
const paramsToObject = (entries) => {
const result = {};
for (const [key, value] of entries) {
result[key] = value;
}
return result;
};
const verifyProxy = (request, env) => {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const hmac = searchParams.get('signature');
const entries = searchParams.entries();
const params = paramsToObject(entries);
const toVerify = Object.entries(params)
.filter(([key]) => key !== 'signature')
.map(([key, value]) => `${key}=${value}`)
.sort((a, b) => a.localeCompare(b))
.join('');
const calculatedHmac = crypto.createHmac('sha256', env.SHOPIFY_API_SECRET)
.update(toVerify)
.digest('hex');
return calculatedHmac === hmac;
}
export default {
async fetch(request, env, ctx) {
return new Response(verifyProxy(request, env));
}
};
Am I missing something as I’d like to use the node module so I can make product requests.
Thanks in advance.
Jack