Search code examples
apirestful-authenticationjscriptsms-gatewayplivo

Authenticating REST calls to Plivo using WSH


My application uses any of the WSH active scripts registered on my customers' systems. This usually means only VBScript and JScript. Sometimes Python, rarely Perl. But only VBScript and JScript are absolutely certain to be installed on a customer's system. And now I need that application to send out SMS messages.

I figured I'd call the Plivo API using pure JScript. No external libraries (i.e. jQuery), no external application/server (i.e. NodeJS). Just plain XMLHTTP requests because I don't know what's installed on my customers' systems and I don't want to have them install anything.

Plivo's API documentation explains pretty much how to do everything... except the authentication part! It simply states you should use Basic authentication on each call, using your AUTHID and AUTHTOKEN. But there is no example for it.

Since Plivo provides a Python Helper library, and I happen to have Python on my dev environment, I first made sure I could get everything going smoothly, so I installed their helper library, grabbed their Python code sample, put in my own ID and Token, and I managed to send myself a SMS Message:

import plivo

auth_id = "MY_AUTH_ID"
auth_token = "MY_AUTH_TOKEN"
p = plivo.RestAPI(auth_id, auth_token)

params = {
    'src': '15556667777',
    'dst' : '15557778888',
    'text' : u"Hello, how are you?"
}
response = p.send_message(params)

Simple enough, and that works great. I figured it would take me 10 minutes to convert that to pure JavaScript (only because I'm a slow typist). Well, several hours/days later, I still can't get it to run and always get a 401 (unauthorized) error response. Here's the code I first tried:

var plivo_authID =    "MY_AUTH_ID";
var plivo_authToken = "MY_AUTH_TOKEN";
var plivo_msgURL =    "https://api.plivo.com/v1/Account/"+plivo_authID+" /Message";

var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0");
xhr.open("POST", plivo_msgURL, false);
xhr.setRequestHeader("Authorization", "Basic " + btoa(plivo_authID + ":" + plivo_authToken));
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send('{"src": "15556667777", "dst" : "15557778888", "text" : "My first Plivo API test"}');

This fails at the send() statement. The only suggestion I received from Plivo support was to include username/password in the open() statement parameters

So I changed my code to:

var plivo_authID =    "MY_AUTH_ID";
var plivo_authToken = "MY_AUTH_TOKEN";
var plivo_msgURL =    "https://api.plivo.com/v1/Account/"+plivo_authID+" /Message";

var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0");
xhr.open("POST", plivo_msgURL, false, plivo_authID, plivo_authToken );
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send('{"src": "15556667777", "dst" : "15557778888", "text" : "My first Plivo API test"}');

But this results in a 401 error. I have done Basic authentication a zillion times with code similar to the above (most notably when calling my application's own API!), but I just can't get it to work with Plivo.

I have tried different combinations of RequestHeaders (including adding Content-Size), removing btoa(), converting the url to the archaic https://username:password@URL syntax, and so many other permutations that I can't recall them all. Still the same result: 401.

Note that my ID/Token/Phone Numbers/URL are all good, since I can use them in my Python code. The only thing I just can't manage to mimic in JavaScript is the authentication part.

Can anyone with Plivo experience help me out? Also, please do not ask me if I've tried with NodeJS, with jQuery or with some other external library. I did, I used Python for testing purposes. But I need to implement this using the only tools that I know are available on my customers' machines, and that's JScript.


Solution

  • Well after letting this issue simmer for a few days, I returned to it this morning and resolved it within a few minutes. The problem was with the URL I was specifying: I never realized I had one extra space before the last "/Message" part of the URL, which obviously caused the REST call to fail.

    So I fixed it but I still couldn't get the call to work: I was receiving a 200 status (which is a successful return code) but the API stated I should receive a 202... and besides the SMS was never received on my phone. Looking through the API, I realized that I was getting the exact same reply and objects I should have received if I had issued a GET statement... which was strange since my code was indeed issuing a POST.

    I then realized I had forgotten to add the trailing backslash to my URL ("/Message/"), which somehow caused the Plivo Server to respond as if I had issued a GET statement.

    So in the end, I changed the URL to:

    var plivo_msgURL =    "https://api.plivo.com/v1/Account/"+plivo_authID+"/Message/";
    

    and that was that.

    The entire, correct code for sending a SMS message is therefore:

    var plivo_authID =    "MY_AUTH_ID";
    var plivo_authToken = "MY_AUTH_TOKEN";
    var plivo_msgURL =    "https://api.plivo.com/v1/Account/"+plivo_authID+"/Message/";
    
    var xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0");
    xhr.open("POST", plivo_msgURL, false, plivo_authID, plivo_authToken );
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.send('{"src": "15556667777", "dst" : "15557778888", "text" : "My first SUCCESSFUL Plivo API test!!!"}'
    

    Hope the above will save other distracted coders the hours of pain I went through... :)