How to generate an HMAC-SHA256 hash in base64?

Topic summary

Problem: Users need to generate an HMAC-SHA256 hash in base64 format for a third-party integration in Shopify Liquid, but the generated signature doesn’t match the expected output.

Root Cause Identified: The issue stems from Shopify Liquid’s base64_encode filter, which converts text to base64 rather than hexadecimal to base64. The hmac_sha256 filter outputs a hex string, but Liquid’s base64 encoding treats it as plain text, causing incorrect conversion.

Solution Found: Schmidtc63 discovered that using JavaScript instead of pure Liquid resolves the problem. By implementing the HMAC-SHA256 and base64 conversion in JavaScript (client-side), the correct 44-byte hash is generated that matches third-party expectations.

Implementation: The workaround involves adding JavaScript code to any theme liquid file where the hash is needed, rather than relying on Liquid’s built-in encryption filters.

Status: The discussion confirms Shopify’s Liquid encryption libraries lack proper hex-to-base64 conversion functionality, making JavaScript the necessary alternative for this use case.

Summarized with AI on November 13. AI used: claude-sonnet-4-5-20250929.

I’m trying to generate an HMAC-SHA256 hash in base64 to use with a 3rd party integration. The hash needs to be appended to the end of the URL in an iFrame on the page, and is created from the URL query parameters and values.

I’m pretty sure I’m clashing with data types, where a hexadecimal value is being converted to UTF-8 and therefore affecting the base64 conversion. I’m reaching the end of my experience, so looking for some suggestions.

Example code:

{% assign queryString = "ShopifyID" | append: customer.id %}
{% assign secretKey = "[Shared secret]" %}

{% assign hashSignature = {{queryString | hmac_sha256: secretKey | base64_encode | url_encode}} %}

<iframe src="https://[Resource URL]?ShopifyID={{customer.id}}&signature={{hashSignature}}"></iframe>

The issue I have is that the signature generated in liquid does not match with the 3rd party, where the result should be 44 characters in length, however, the result I get from the liquid code above is 88.

I’ve run the same parameters through an external site as well as in javascript and these produce the same result as the third party. Jscript runs client-side, and I haven’t been able to find a way to use this either due to iFrame load timing, or having the pass through the secret key to the browser.

Using some random number generators for the customer.id and secret key, I can get the following:

queryString = ShopifyID5184202623769

Secret Key = 9b98935d8fe6a6aa907046efdd070449

Expected output = Rjn1Ub1Mw2GGiCwclOqBzs4+LaB76dhPvsKqD0xda4I=

Liquid output = NDYzOWY1NTFiZDRjYzM2MTg2ODgyYzFjOTRlYTgxY2VjZTNlMmRhMDdiZTlkODRmYmVjMmFhMGY0YzVkNmI4Mg==

Did you ever figure this out? I’m running into the same issue.

1 Like

Sadly, no.

As best I can tell, these particular Liquid encryption libraries are not included in Shopify’s Liquid.

Similarly, if you do find something, I would be happy to hear!

1 Like

So, the hash is working fine. It’s the conversion to base64. hmac generates a hex string. But, the liquid to Base64 is strictly text to Base64, not hex to base64. So, I did this:

{% liquid
   assign gcHash="some thing I want to hash" | hmac_sha256: "my secret code"
%} 

That took care of it. I got the correct 44-byte hash I was looking for.

I’m having the same issue but can’t figure out where I need to paste this code to fix it

In any theme liquid file where you need this.