angularamazon-web-servicesaws-lambda

Getting 'blocked by CORS policy' error while adding authentication from AWS


I have a code which uses aws-amplify and authenticates.
Code:

signRequest(host: any, path: any, method: any, accessKey: any, secretKey: any, region: any, service: any) {
    const amzDate = this.getAmzDate();
    const dateStamp = this.getDate();      // Prepare canonical request      
    const canonicalURI = path;
    const canonicalQueryString = '';  
    const canonicalHeaders = `host:${host}\n` + `x-amz-date:${amzDate}\n`;
    const signedHeaders = 'host;x-amz-date';
    const payloadHash = CryptoJS.SHA256('').toString(CryptoJS.enc.Hex);
    const canonicalRequest = `${method}\n${canonicalURI}\n${canonicalQueryString}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
    console.log("Canonical Request:", canonicalRequest);
    // String to sign    
    const algorithm = 'AWS4-HMAC-SHA256';
    const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
    const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${CryptoJS.SHA256(canonicalRequest).toString(CryptoJS.enc.Hex)}`;
    console.log("String to Sign:", stringToSign);
    // Signature    
    const signingKey = this.getSignatureKey(secretKey, dateStamp, region, service);
    const signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);
    console.log("Calculated Signature:", signature);
    // Authorization header     
    const authorizationHeader = `${algorithm} Credential=${accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
    console.log("authorization success",authorizationHeader)
    return {
      'Content-Type': 'text/plain',
      'x-amz-date': amzDate,
      'Authorization': authorizationHeader
      // 'x-amz-security-token': sessionToken  // Optional, if using session-based access     
    };
  }  
getSignatureKey(key: string, dateStamp: string | CryptoJS.lib.WordArray, region: string | CryptoJS.lib.WordArray, service: string | CryptoJS.lib.WordArray) {
  const kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
  const kRegion = CryptoJS.HmacSHA256(region, kDate);
  const kService = CryptoJS.HmacSHA256(service, kRegion);
  const kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
  console.log("k signing key",kSigning)
  console.log("get Signature key:", this.getSignatureKey);
  return kSigning;  
// Define your AWS and API details   
 host = 'https://2ydk2p26dbv2ak5fygphvcb6ey0dzrzm.lambda-url.us-east-1.on.aws/';
 path = '/';
 method = 'POST';
 region = 'us-east-1';
 service = 'lambda';
 accessKey = '****';
 secretKey =  '****';
//  sessionToken = '';    // Generate signed headers  
 new_headers = this.signRequest(this.host, this.path, this.method, this.accessKey, this.secretKey,this.region, this.service);  

When I run that, I get this error:

Access to XMLHttpRequest at 'https://2ydk2p26dbv2ak5fygphvcb6ey0dzrzm.lambda-url.us-east-1.on.aws/' from origin 'https://function-url-ver2-1.d2qo24bmjgejow.amplifyapp.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What should I change to make it?


Solution

  • The issue is that your lambda is not sending CORS(Cross origin resource sharing) headers as a response to the preflight(OPTIONS) call done by your browser. You can read more about the exact rules of CORS here(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).

    You can setup a cors configuration in the lambda console, if you are using cdk to deploy the function url it is a field in the props, if you're using plain cloudformation it's a field in the function url config too.

    https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-url.html

    https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.FunctionUrl.html

    You will need to add at least an allowed origin, if you want to allow all origins you can use *

    You will probably also need to add the allowed Http Methods and headers you are sending with the request.

    A different solution would be to also make this lambda function url available through the same cloudfront distribution as your amplify app. They would have the same host and not require CORS

    https://aws.amazon.com/blogs/networking-and-content-delivery/using-amazon-cloudfront-with-aws-lambda-as-origin-to-accelerate-your-web-applications/