Clean Instagram oauth using node.js and express and minimal middlewares

I am trying to get a clean Instagram oauth without relying on middlewares such as passport, or instagram-node to learn the process and have maximum control. I have been trying to follow instagram Server-side (Explicit) Flow, which is a 2 step operation:

  1. request an access code
  2. request an access token

right now my server is set up using:

express         = require('express'),
app             = express();

and to initiate the first step I am using :

app.get('/', function(req, res){
  var url = 'https://api.instagram.com/oauth/authorize/?client_id='+CLIENT-ID+'&redirect_uri='+YOUR-REDIRECT-URI+'&response_type=code'
  res.redirect(url);
});

The above step sends me properly to instagram for authentication and the redirect callback of instagram gets picked up bellow at which point the console.log does display the correct instagram code. But the res.set part is wrong and does not work.

app.get('/auth/instagram/callback', function(req, res){

  console.log('/// here to keep track of how many times this is called');
  console.log('Instagram code: ', req.query.code);

  var url = 'https://api.instagram.com/oauth/access_token';

  res.set({
   'client_id' : 'CLIENT-ID',
   'client_secret' : 'CLIENT-SECRET',
   'grant_type' : 'authorization_code',
   'redirect_uri' : 'YOUR-REDIRECT-URI',
   'code' : req.query.code
  }).redirect(url);

});

Unfortunately it hangs at this point and clearly does not provide back the right data back.

Instagram suggest to do the following, but I am unsure how this would translate in express:

curl \-F 'client_id=CLIENT-ID' \
  -F 'client_secret=CLIENT-SECRET' \
  -F 'grant_type=authorization_code' \
  -F 'redirect_uri=YOUR-REDIRECT-URI' \
  -F 'code=CODE' \https://api.instagram.com/oauth/access_token

Any insight on this would be most welcome!

Thank you for your help.

I would suggest studying passport code (and instagram in particular).

In any case, after getting the code back (which works for you), you need to send a request from your backend code to Instagram. So your code would look more like (top of my head):

app.get('/auth/instagram/callback', function(req, res){

  console.log('/// here to keep track of how many times this is called');
  console.log('Instagram code: ', req.query.code);

  var data = {
   'url': url
   'client_id' : 'CLIENT-ID',
   'client_secret' : 'CLIENT-SECRET',
   'grant_type' : 'authorization_code',
   'redirect_uri' : 'YOUR-REDIRECT-URI',
   'code' : req.query.code
  };

  var url = 'https://api.instagram.com/oauth/access_token';

  request.post({
  method: 'POST',
  url: url,
  body: JSON.stringify(data),
  },
  function (e, r, body) {
    //body will contain the access_token
   });
});

Then after you get the token you can set session, etc.

Ok got it to work to do post request for specific API calls but not yet the OAUTH part.. and WITH instagram secure header.

This exemple is to follow a user when you have an access token for a user.

var crypto      = require('crypto'),
    request     = require('request');

var hmac = crypto.createHmac('SHA256', 'INSTAGRAM_CLIENT_ID');
    hmac.setEncoding('hex');
    hmac.write('IP_ADDRESS_127.0.0.1_OR_12.34.56.78');
    hmac.end();
var hash = hmac.read();

// Set the headers
var headers = {
    'X-Insta-Forwarded-For': 'IP_ADDRESS_127.0.0.1_OR_12.34.56.78|'+hash
}

// Configure the request
var options = {
    uri: 'https://api.instagram.com/v1/users/1234/relationship_ OR WHATEVER API CALL',
    qs: {'access_token': 'INSTAGRAM ACCESS TOKEN'},
    method: 'POST',
    headers: headers,
    form:{action:'follow'}
}

request(options, function (error, response, body) {
    // body response is what you are interested in

    // NOTE that the body info is a string response so use var your_variable = JSON.parse(body) to use it as an object.

    // Some exemples bellow

    // USER NOT EXISTANT
    // {"meta":{"error_type":"APINotFoundError","code":400,"error_message":"this user does not exist"}}
    //
    // successful response from unfollow
    // {"meta":{"code":200},"data":{"outgoing_status":"none","target_user_is_private":false}}
    //
    // NOT FOLLOWING OR FOLLOWED BY
    // {"meta":{"code":200},"data":{"outgoing_status":"none","target_user_is_private":false,"incoming_status":"none"}}
    //
    // you are following user 1234 but not followed back by them
    // {"meta":{"code":200},"data":{"outgoing_status":"follows","target_user_is_private":false,"incoming_status":"none"}}
    //
    // Following and followed by
    // {"meta":{"code":200},"data":{"outgoing_status":"follows","target_user_is_private":true,"incoming_status":"followed_by"}}
    //
    // PRIVATE users
    // {"meta":{"code":200},"data":{"outgoing_status":"requested","target_user_is_private":true}}

});

I hope this helps.

And here is the actual response for the second part of OAuth with Instagram! Might not

var data = {'client_id' : process.env.FANCRAWLCLIENTID,
             'client_secret' : process.env.FANCRAWLCLIENTSECRET,
             'grant_type' : 'authorization_code',
             'redirect_uri' : process.env.INSURIREDIRECT,
             'code' : req.query.code
            };

// Configure the request
var options = {
    uri: 'https://api.instagram.com/oauth/access_token',
    method: 'POST',
    form: data
}

request(options, function (error, response, body) {

  // to convert the string body to a usable object
  var pbody = JSON.parse(body);

  // pbody should look like this:      
  // {"access_token":"8943851.83434d.697342341324jkfdjsf41afd784932a2e8",
  //   "user":
  //     {"username":"my_user_name",
  //     "bio":"blah blah...",
  //     "website":"http:\/\/www.something.com",
  //   "profile_picture":"http:\/\/images.ak.instagram.com\/profiles\/profile_851_73sq_115.jpg",
  //     "full_name":"Full Name",
  //     "id":"8943851"}
  //   }

});

Enjoy!!!