0

I'm having a signature mismatch issue when attempting to use signed URLs within image tags in an aura component. I call the controller to calculate the signed URLs for a number of different image links, then attempt to render these on-page after load. However, I will occasionally get 403 errors on image loads. Navigating to the S3 XML, I see:

<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

The weird thing here, though, is that the failures are VERY inconsistent. For example, on a page with 10 images, somewhere between 2-5 will not load. The ones that fail vary as well; what may fail on one page load seemingly succeeds on another.

I figured I'd reach out here to see if anyone has encountered similar issues. Any help is greatly appreciated! Code below.

Apex Controller:

public static List<String> getSignedURLs(List<String> files) {
    List<String> fileNames = new List<String>{};
    List<String> signedUrls = new List<String>{};
        
    for(String f: files) {
        fileNames.add(EncodingUtil.urlEncode(f, 'UTF-8'));
    } 

    S3_Settings__c s3 = S3_Settings__c.getInstance(p.Id);  
    String BucketName= s3.Photo_Bucket__c;
    String AccessKey = s3.s3Key__c;
    String SecretKey = s3.s3Secret__c;

    Datetime now = DateTime.now();
    Datetime expireson = now.AddSeconds(300); // Lifespan of the link
    Long Lexpires = expireson.getTime()/1000;
    for(String fileName: fileNames) {
        String stringtosign = 'GET\n\n\n'+Lexpires+'\n/'+BucketName+'/'+filename;
        System.debug('redirectToS3Key stringstosign: ' + stringtosign);            
        String signingKey = EncodingUtil.base64Encode(Blob.valueOf(SecretKey));
        Blob mac = Crypto.generateMac('HMacSHA1', blob.valueof(stringtosign),blob.valueof(SecretKey)); 
        String signed= EncodingUtil.base64Encode(mac);     
        String codedsigned = EncodingUtil.urlEncode(signed,'UTF-8');
        String url = 'http://'+BucketName+'.s3.amazonaws.com/'+filename+'?AWSAccessKeyId='+AccessKey+
            '&Expires='+Lexpires+'&Signature='+signed;
        signedUrls.add(url);
    } 
    return signedUrls; 
}

JS Controller:

  var signAction = component.get("c.getSignedURLs");
            signAction.setParams({
                files: urls
            });
            signAction.setCallback(this, function(signedURLsResponse) {
                var signed = signedURLsResponse.getReturnValue();
                for(var p = 0; p < result.memberCommunications.length; p++) {
                    if(result.memberCommunications[p].URL__c != null) {
                        result.memberCommunications[p].SignedURL = signed[p];
                    }
                }
                component.set("v.loadImage", true);
            });
            $A.enqueueAction(signAction);
            component.set("v.correspondances", result.memberCommunications);

And finally, rendering in aura:

<aura:if isTrue="{!comm.URL__c != null}">
    <div class="slds-from-member slds-mms">
       <aura:if isTrue="{!v.loadImage}">
          <img src="{!comm.SignedURL}"></img><!-- render signed image URL -->
       </aura:if>
          <span class="">{!comm.Body__c}</span>
     </div>
      <aura:set attribute="else">
      <div class="slds-from-member">
         <span class="">{!comm.Body__c}</span>
      </div>
       </aura:set>
  </aura:if>
0

Please see this answer: AWS Cloudfront Signed URL from Apex

Essentially you need to make sure your joined string URL doesn't have any URL reserved characters.

1
  • Thanks for this, got me looking at the right section of code. The 403s when away after I swapped out the variable "signed" for "codesigned" in the url. Turns out it's helpful to actually use your URL Encoded strings, rather than define them and forget about them :) Just something to note for anyone that uses that boilerplate Apex code... Mar 5 at 18:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.