Monthly Archives: July 2016

Digikey API and OAuth

OAuth is harder than expected. I’m just going to jot down some notes as I go:

node interpreter is very useful for quickly testing out packages! Just run “node” from the command line. “.exit” quits the interpreter.

A nice way to keep secrets in a node system is in a file, with good system permissions. If you make the file follow the JSON file format:

{
  "key": "value",
  "key_of_set": ["value1", "value2"],
  "key_of_dict": {"keys_forever": "values too"}
}

AND GIVE THE FILE A .JSON ENDING

then running:

var file_json = require("path_to_file.json")

loads your object into file_json.

Versioning this secret file is fun. You can make a dummy file, with something like "secret_key": "mtwannahuckaloogie" git add that file, then put the file on a .gitignore and run:

git update-index --assume-unchanged 

and git will ignore it forevermore! (I think. Probably try not to shake your index too hard or you might leak it)

The usual package protocol:

npm install --save simple-oauth2

gets the app ready for action! (i hope)

The OAuth demo code on the npm page for simple-oauth2 is pretty straightforward, I basically copy pasted it, along with the relevant clientID and clientSecret given by digikey.
Unfortunately, my hope for having the callback address of 127.0.0.1:3000 work, was a bust. Looks like tomorrow I’ll need to do some funny business to open up some ports :O

Ok, the redirect isn’t accessed by Digikey, its simply stuffed into the user’s browser. This is good, I was just being an idiot on the config side at Digikey. When Digkey asked for my apps redirect callback URI, I gave it 127.0.0.1:3000/callback. the user was then sent to their own port 3000, obviously wrong it should go to my webserve’s port 3000. for me on lan, that means 192.168.x.x:3000/callback. This works better, gets me to digikey’s login.

HOWEVER, Digikey wants an https address for the callback (doesn’t look required by oauth since the demo code uses http), so I guess I need to set up https for the app. Since I’m not paying the big bucks for getting a cert from a CA (though I could get one from MIT for the next year), I’ll just self-sign one. Instructions on that can be found at: https://github.com/nodejitsu/docs/blob/master/pages/articles/HTTP/servers/how-to-create-a-HTTPS-server/content.md

I’ll lay down the gist here though since that url seems unstable

openssl genrsa -out key.pem
openssl req -new -key key.pem -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
rm csr.pem

MAKE SURE TO DEFEND THEM FROM YOUR VERSIONING SYSTEM!
The package ‘https’ will automatically manage the remainder of the connection stuff. If you’ve used the express directory formatter/file autogen thing, then you’ll want to edit your /bin/www.

adding:

var https = require('https');
var fs = require('fs');

var https_config = {
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
};

var https_server = https.createServer(https_config, app);

https_server.listen(4433);

And replacing the port in listen() with the port you want. Make sure create_server goes after the var app = express(); line.

The https stuff was a problem, as Digikey won’t accept a redirect without ssl, but not the big problem. Even after getting that set up, I kept getting ERROR 402’s all the time. I had subscribed to the API’s using the kind of hidden buttons on the Digikey API page, and was flummoxed at what the problem was. “PAYMENT_REQUIRED”? Sometimes this error is used for APIs you have exceeded quotas on or need to pay for. Adding some console.logs to the simple-oauth library, I extracted the full reply from the server:

The client MUST NOT use more than one authentication method in each request.

Huh? I thought I was only using one… I dumped the POST request parameters just before they were sent (also by throwing a console.log into the library files) and noticed Authorization: Basic ... in there with a huge hash of some kind. Crap! There’s a default token of some kind coming from simple-oauth2, you just have to add

useBasicAuthorizationHeader: false

to the config parameters for simple-oauth2, and then you /just/ have the authentication code coming in. FIXED!

Mouser SOAP

You can buy a lot on Mouser, but unfortunately I don’t think there is soap. You can, however, get SOAP from Mouser; that is, Simple Object Access Protocol, an API standard. Signing up for dev access at http://www.mouser.com/apihome/ lets you use more automated format requests, hopefully faster that using the site. Also, most importantly, gives you programmatic access to the data if using a SOAP module in you webapp, such as soap for NPM.

By gym.king (001_MG_2576_(015)) [CC BY-SA 2.0 (http://creativecommons.org/licenses/by-sa/2.0)], via Wikimedia Commons

This mouser needs a bath.


setup SOAP as an app dependency:

npm install soap --save

SOAP basically grabs an XML doc from somewhere (disk or web, usually ending in WSDL), reads it to determine what commands are available and what inputs they need, then calls one and returns the reply. Mouser has its API file at http://www.mouser.com/service/searchapi.asmx?WSDL. If you follow the link there, you can read each of the commands, also described in the human-readable API page: https://www.mouser.com/service/mousersearchapi.asmx

The node SOAP module is /super easy/ once you know how to use it, the doc was a little vague for my tastes. The procedure is this:

soap.createClient("url_to_xml_WSDL", callback_fun);

This createClient isn’t a long lived thing, its just for the duration of this one request and callback. There is no client object to store. The callback is called immediately upon client creation, so we pass an anonymous function in reality.

soap.createClient("url_to_xml_WSDL", function(err, client){
  client.MyFunction(args, callback);
});

client.MyFunction will look for MyFunction in the returned XML API sheet, and draw up a request with MyFunction, and the appropriate args fields filled in. The response will be returned into this callback function, which for ease we will create right here with another anonymous function. For the basic Mouser API, ServiceStatus is a valid function, taking no arguments. This yields:

soap.createClient("url_to_xml_WSDL", function(err, client){
  client.ServiceStatus({}, function(err, result){
    console.log(result);
  });
});

and if url_to_xml_WSDL was the correct one for Mouser as listed above, you should get back a dict with {ServiceStatusResult: true}

Congratulations!