base64url encoding for hmac function

Having this piece of code,

 

    <AssignVariable>
        <Name>hmac.computed_base64</Name>
        <Template>{hmacSha256(private.hmacSecretKey,hmac.stringToSign,'utf-8','base64')}</Template>
    </AssignVariable>

 

 

how can i get this base64URL encoded, and not simple base64 encoded?

1 3 595
3 REPLIES 3

Sadly! There is no 'base64url' encoding in the HMAC function within Message Templates.  This is a deficiency in the function. We have a bug in the backlog to fix that, but it's not included yet in the runtime. (ref: b/178413059)

But there is an HMAC Policy that can deliver base64url encoded results. The documentation for the policy shows that.  Try it. 

screenshot-20220216-095114.png

Hi @dchiesa1 

I see an issue with the base64url encoding in HMAC policy. It is generating the HMAC containing a equals (=) symbol.

It is not compatible if we include in VerificationValue node, a hash generated with other libraries like Apache commons. As per their documentations and sourcecode, the encoding-decoding tables do not even contain equals symbol?

Is there any recommendation that HMAC policy should be used only if HMAC value is generated using JS or node.js?

Yes, you are correct. That's a limitation of the HMAC policy when dealing with base64url encoding. The relevant spec for Base64 indicates that the padding character (the = character) can optionally be omitted in some cases. But the Apigee HMAC policy does not consider that. It does not allow for omitting the padding. Thanks for pointing that out. Here is an internal reference to the bug: b/220926371

The workaround is to use the HMAC policy to generate the HMAC, and then verify it separately in a JS step.  Like this: 

  <Step>
    <Name>HMAC-Generate-HMAC-Value</Name>
  </Step>
  <Step>
    <Name>JS-Compare-HMAC-to-Expected-Value</Name>
  </Step>

 And the JS would look like this: 

var expected = context.getVariable('expected-hmac-value');
var calculated = context.getVariable('hmac-calculated-value');
var stripped = calculated.replaceAll('=','');
if (expected != stripped) { 
  throw new Error('HMAC mismatch');
}