Proxying Instagram API Requests

As you can probably imagine, here at Later we have cause to make use of the Instagram API on occasion. In an effort to provide a more secure experience for our users we moved our Instagram API requests to Secure Requests.

We’ll be explaining this over two blog posts. This first post will be about setting up a basic Node/Express app that will proxy and sign Instagram API requests. We have set up a sample app on our GitHub page and will be referencing it throughout the blog post.

We already had a small Node/Express app running for some other services, so this seemed like a great place to add our proxy. The fact that http-proxy-middleware exists and makes this super easy, was a huge benefit as well.

The Node/Express Code

You can see our basic node app here. There are only a few lines here that are not part of a standard Express app setup. I’ve highlighted some of the lines of importance below.

Line 4 is where we require our own proxy code.

var instagramProxy = require('./proxies/instagram');

Lines 5&6 and 22 will be important in another blog post on securing your proxy with Javascript Web Tokens.

Line 7 gets us some config variables.

var config = require('./config')();

Line 19 wires up our Instagram proxy.

app.use(instagramProxy('/proxy/instagram', config['INSTAGRAM_CLIENT_SECRET']));

The great thing about this setup is that we don’t have to do anything crazy or weird. All of our code is isolated in its own little module. We just require that module to use it as middleware.

The Instagram Proxy

Now let’s take a closer look at our proxy middleware. The file is a bit too long to include everything here, but the source is pretty well commented. If you want to open it up in another tab and follow along, you can find the source here.

The requires are pretty straightforward. We use http-proxy-middleware to handle all of the heavy lifting of the actual proxy. crypto is for signing the request, and url and querystring are for manipulating the url and query parameters.

var proxy = require('http-proxy-middleware');
var crypto = require('crypto');
var url = require('url');
var querystring = require('querystring');

Request Signature

The whole reason we are doing this proxy thing is so that we can sign our Instagram API requests. We do this with the requestSignature function.

It’s pretty straightforward:

  1. Check to make sure we have the secret to sign the request with. (L29-33)
  2. Chop off the /v1 from the front of the path. (L35-37)
  3. Sort all of the query/body parameters. (L41)
    • Sorting is done with sort_object, which I am pretty sure I just yanked from SO, or one of any number of other blog posts.
  4. Create string to sign. (L42-46)
  5. Create the signature. (L48-50)

Request Rewrite

The more “fun” stuff starts on line 65 in igProxy. This is where we actually do the proxy. The proxyPath parameter is what we pass in when we use the middleware for the Express app. In this case we pass in /proxy/instagram. With the way we have have our proxy middleware set up, our requests will get translated like this:

  • https://proxy.example.com/proxy/instagram/users/self
    • https://api.instagram.com/v1/users/self
  • https://proxy.example.com/proxy/instagram/media/12345/likes
    • https://api.instagram.com/v1/media/12345/likes

Since GET and DELETE requests use query params we simply pull them out using querystring and pass them to our requestSignature method along with the path and the signing secret. Then we just tack the signature on to the end. Nice and neat.

POSTs are a bit different. Making use of body-parser, we can pull out the parameters we need to create our signature. We create the request signature in the same way as before, and then we add it to the new body object. We also need to update the headers for the content-type and content-length since we have monkeyed with the payload.

Boom. Done. Your Instagram API requests are now signed via your proxy and there was much rejoicing! Making signed API requests through a proxy has been a nice learning experience for us, but more importantly it has been an opportunity to increase our app’s security and protect our users’ privacy.

You can find all of the source code for this blog post and some more detailed instructions here.

But Wait, There’s More

You might have noticed that there is no auth on the proxy itself. We tackled that as well. We didn’t want a malicious script to be able to get a hold of our access tokens and be able to use our proxy server all willy-nilly.

Next up: Securing your proxy server with Javacript Web Tokens!