amazon-chime-sdk-js icon indicating copy to clipboard operation
amazon-chime-sdk-js copied to clipboard

CORS error and 403 (Forbidden) when we call https://service.chime.aws.amazon.com/meetings API

Open akshay-mirgal-i opened this issue 4 years ago • 2 comments

When we call into the postman is working fine But not in actual code, Give cors error and 403 (Forbidden).

For example 1 : I'm using single Js and created following code.


async function requestTest(credentials, request) {
    console.log("canonical1: ");
    let url = new URL(request.url);
    let date = new Date();
    credentials.host = url.host;
    request.route = url.pathname;
    let canonical = await this.canonicalRequest(credentials, request, date)
    console.log("canonical: ", canonical);
    let toSign = await this.requestToSign(canonical, credentials, date)
    console.log("toSign: ", toSign);
    let signature = await this.signature(toSign, credentials, date)
  
    return {
      "x-amz-date": await this.amzLongDate(date),
      Authorization:
        "AWS4-HMAC-SHA256 Credential=" +
        credentials.accessKeyId +
        "/" +
       await this.amzShortDate(date) +
        "/" +
        credentials.region +
        "/chime/aws4_request, " +
        ("SignedHeaders=host;x-amz-content-sha256;x-amz-date" +
          (credentials.token ? "x-amz-security-token" : "") +
          ", Signature=" +
          signature),
      "Content-Type": "application/json",
      "x-amz-security-token": credentials.token || undefined
      // host: this.credentials.host,
    };
  }


async function canonicalRequest(credentials, request, date) {
    return (
      "\n" +
      (request["method"]).toUpperCase() +
      "\n" +
      (request.route.charAt(0) !== "/" ? "/" + request.route : request.route) + //
      "\n" +
      this.queryParameters(request.query) +
      "\ncontent-type:application/json\nhost:" +
      credentials.host +
      "\n" +
      ("x-amz-date:" +
      this.amzLongDate(date) +
        "\n" +
        (credentials.token
          ? "x-amz-security-token:" + credentials.token + "\n"
          : "") +
        "\n") +
      ("host;x-amz-content-sha256;x-amz-date" +
        (credentials.token ? ";x-amz-security-token" : "") +
        "\n") +
        this.hashString(request["body"])
    );
  }


  async function requestToSign(cRequest, credentials, date) {
    return (
      "" +
      "AWS4-HMAC-SHA256" +
      this.amzLongDate(date) +
      "" +
      this.amzShortDate(date) +
      "/" +
      credentials.region +
      "/chime/aws4_request" +
      this.hashString(cRequest)
    );
  }


async function signature(toSign, credentials, date) {
  var kDate = sign(this.amzShortDate(date), "AWS4" +  credentials.secretAccessKey);
  var kRegion = sign(credentials.region, kDate);
  var kService = sign("chime", kRegion);
  var kSigning = sign("aws4_request", kService);
  var kSigning2 = sign(toSign, kSigning);
  return kSigning2;
}


  async function queryParameters(queryParameterObj) {
    var pieces = [];
    if (queryParameterObj) {
      Object.keys(queryParameterObj)
        .sort()
        .forEach(function(k) {
          return pieces.push(
            k + "=" + encodeURIComponent(queryParameterObj[k])
          );
        });
    }
    return pieces.length > 0 ? pieces.join("&") : "";
  }


  async function hashString(str) {
    return CryptoJS.SHA256(str).toString();
  }

  async function hmac(key, value) {
    return CryptoJS.HmacSHA256(""+value, ""+key).toString();
  }

  async function sign(key, msg) {
    return CryptoJS.HmacSHA256(""+key, ""+msg, {asBytes: true}).toString();
  }

  async function amzShortDate(date) {
    return this.amzLongDate(date).substr(0, 8);
  }

  function amzLongDate(date) {
    return  date.toISOString()
      .replace(/[:\-]|\.\d{3}/g, "")
      .substr(0, 17);
    }

     var  credentials = {
                "region":"us-east-1",
                "accessKeyId":"XXXXX",
                "secretAccessKey":"XXXX",
                "host": "",
                "token": null
              }

              var   request = {
                "url": "https://service.chime.aws.amazon.com/meetings",
                "type": "POST",
                "method": "POST",
                "dataType": "json",
                "contentType": "application/json",
                "data": {"ClientRequestToken":"12345678912","ExternalMeetingId":"meeting123","MediaRegion":"ap-south-1"},
                "route": "",
                "query": null,
                "body": null
              }

           await requestTest(credentials,request).then(function(result) {
          var myHeaders = new Headers();
          myHeaders.append("X-Amz-Content-Sha256", "XXXXXX");
          myHeaders.append("X-Amz-Date",result["X-Amz-Date"]);
          myHeaders.append("Authorization",result["Authorization"]);
          myHeaders.append("Content-Type", "application/json");
          myHeaders.append("Accept", "application/json");
          myHeaders.append("Access-Control-Allow-Origin", "*");
          myHeaders.append("Access-Control-Allow-Credentials", "true");

          var raw = JSON.stringify({"ClientRequestToken":"12345678912","ExternalMeetingId":"meeting123","MediaRegion":"ap-south-1"});
          
          var requestOptions = {
            method: 'POST',
            headers: myHeaders,
            body: raw,
            redirect: 'follow'
          };  

         fetch("https://service.chime.aws.amazon.com/meetings", requestOptions)
            .then(response => response.text())
            .then(result => console.log(result))
            .catch(error => console.log('error', error));
      });
       

*For example 2 : Call following code with 5 min (Authorization valid for 5 min ) which is available is postman *


  var myHeaders = new Headers();
        myHeaders.append("X-Amz-Content-Sha256", "XXXXXX");
        myHeaders.append("X-Amz-Date", "20210506T111414Z");
        myHeaders.append("Authorization", "AWS4-HMAC-SHA256 Credential=XXXXX/20210506/us-east-1/chime/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=XXXXX");
        myHeaders.append("Content-Type", "application/json");
        myHeaders.append("Cookie", "aws-ubid-main=755-4115226-1570161");
        
    var raw = "{\n   \"ClientRequestToken\": \"12345678912\",\n   \"ExternalMeetingId\": \"meeting123\",\n   \"MediaRegion\": \"us-east-1\"\n}";
var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: raw,
  // mode: "no-cors",
  redirect: 'follow'
};

fetch("https://identity-chime.us-east-1.amazonaws.com/meetings", requestOptions)
  .then(response => console.log('result123',JSON.stringify(response)))
  .then(result => console.log('result123',result))
  .catch(error => console.log('error123', error));

*Access to fetch at 'https://identity-chime.us-east-1.amazonaws.com/meetings' from origin 'http://localhost' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. app.js:86 POST https://identity-chime.us-east-1.amazonaws.com/meetings net::ERR_FAILED *

used following both API still facing same issue https://identity-chime.us-east-1.amazonaws.com/meetings https://service.chime.aws.amazon.com/meetings *

akshay-mirgal-i avatar May 06 '21 13:05 akshay-mirgal-i

@akshay-mirgal-i Unfortunately, current meeting APIs are not enabled for CORS. You have to call createMeeting from your backend, similar to the meeting demo https://github.com/aws/amazon-chime-sdk-js/blob/master/demos/browser/server.js#L54.

ltrung avatar May 07 '21 04:05 ltrung

@akshay-mirgal-i I was able to get CORS working in the serverless demo by editing the headers in the handler.js response function:

function response(statusCode, contentType, body, isBase64Encoded=false) {
  return {
    statusCode: statusCode,
    headers: { 'Content-Type': contentType,
               'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
               'Access-Control-Allow-Methods': 'OPTIONS,POST,GET',
               'Access-Control-Allow-Origin': '*'
    },
    body: body,
    isBase64Encoded,
  };
}

Though I will mention that a lot of the POSTs in this demo use only querystrings so the issue may also be that you are trying to provide your params in the body of the request as JSON instead of using quesrystring params.

rrosentratercarnow avatar Sep 21 '21 01:09 rrosentratercarnow