azureazure-communication-services

Azure ACS: CreateCall works but CallMedia Play is unauthorized


I am following this tutorial https://learn.microsoft.com/en-us/azure/communication-services/tutorials/postman-tutorial Using this same code, I called https://learn.microsoft.com/en-us/rest/api/communication/callautomation/create-call/create-call?view=rest-communication-callautomation-2023-10-15&tabs=HTTP and it works perfectly.

Next step, I called https://learn.microsoft.com/en-us/rest/api/communication/callautomation/call-media/play?view=rest-communication-callautomation-2023-10-15&tabs=HTTP with the callConnectionId I obtained from the previous API call.. and I keep getting

{
    "error": {
        "code": "7509",
        "message": "HMAC-SHA256 validation failed"
    }
}

My body for CallMedia-> play is

{
  "playSources": [
    {
      "kind": "text",
      "text": {"voiceKind": "male", "text": "Hello. This is Microsoft calling. If you are trying to authenticate, please press the pound or hash key now", "sourceLocale" : "en-US"}
    }
  ],
  "playTo": [
    {
        "phoneNumber": {
            "value": "+11231230672"
        }
    }
   ]
}

Where am I going wrong?

I tried changing

pm.request.headers.upsert({
    key:'Authorization',
    value: "HMAC-SHA256 SignedHeaders=date;host;x-ms-content-sha256&Signature=" + signature
});

to

pm.request.headers.upsert({ key:'Authorization', value: "HMAC-SHA256 Credential=" + pm.variables.get("credential") + "&SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=" + signature });

But that leads to an "invalid header parameter"

I tried hardcoding endpoint, url .. but no luck.

Can you please help?


Solution

  • The issue with HMAC-SHA256 validation when trying to make a call to the Azure Communication Services (ACS) API for playing media during a call due to invalid key details.

    The following are steps to CallMedia play:

    // Set the Date header to our Date as a UTC String.
    const dateStr = new Date().toUTCString();
    pm.request.headers.upsert({key:'Date', value: dateStr});
    
    // Hash the request body using SHA256 and encode it as Base64
    const hashedBodyStr = CryptoJS.SHA256(pm.request.body.raw).toString(CryptoJS.enc.Base64)
    // And add that to the header x-ms-content-sha256
    pm.request.headers.upsert({
        key:'x-ms-content-sha256',
        value: hashedBodyStr
    });
    
    // Get our previously specified endpoint variable
    const endpoint = pm.variables.get('endpoint')
    // Remove the https, prefix to create a suitable "Host" value
    const hostStr = endpoint.replace('https://','');
    
    // This gets the part of our URL that is after the endpoint, for example in https://contoso.communication.azure.com/sms, it will get '/sms'
    const url = pm.request.url.toString().replace('{{endpoint}}','');
    
    // Construct our string which we'll sign, using various previously created values.
    const stringToSign = pm.request.method + '\n' + url + '\n' + dateStr + ';' + hostStr + ';' + hashedBodyStr;
    
    // Decode our access key from previously created variables, into bytes from base64.
    const key = CryptoJS.enc.Base64.parse(pm.variables.get('key'));
    // Sign our previously calculated string with HMAC 256 and our key. Convert it to Base64.
    const signature = CryptoJS.HmacSHA256(stringToSign, key).toString(CryptoJS.enc.Base64);
    
    // Add our final signature in Base64 to the authorization header of the request.
    pm.request.headers.upsert({
        key:'Authorization',
        value: "HMAC-SHA256 SignedHeaders=date;host;x-ms-content-sha256&Signature=" + signature
    });
    

    Enter image description here

    Call Setup with Cognitive Services:

    POST https://contoso.communications.azure.com/calling/callConnections?api-version=2023-10-15
    Authorization: Bearer {access_token}
    
    {
      "callbackUri": "https://app.contoso.com/callback",
      "targets": [
        {
          "kind": "phoneNumber",
          "phoneNumber": {
            "value": "+919"
          }
        }
      ],
      "sourceCallerIdNumber": {
        "value": "+183"
      },
      "sourceDisplayName": "Contoso Support",
      "callIntelligenceOptions": {
        "cognitiveServicesEndpoint": "https://<your-cognitive-service-endpoint>.cognitiveservices.azure.com/"
      }
    }
    

    Enter image description here

    Play Call with Text-to-Speech:

    POST https://contoso.communications.azure.com/calling/callConnections/{callConnectionId}:play?api-version=2023-10-15
    Authorization: Bearer {access_token}
    
    {
      "playSources": [
        {
          "kind": "text",
          "text": {
            "voiceKind": "male",
            "text": "Hello. This is Microsoft calling. If you are trying to authenticate, please press the pound or hash key now",
            "sourceLocale": "en-US"
          }
        }
      ],
      "playTo": [
        {
          "kind": "phoneNumber",
          "phoneNumber": {
            "value": "+919"
          }
        }
      ],
      "playOptions": {
        "loop": true
      },
      "operationCallbackUri": "https://app.contoso.com/callback"
    }
    

    Output:

    Enter image description here