Update 08/17: Here’s the link to a test project I have made for a simple API connection on my Github.

This post covers possible challenges in connecting a React Native app to a Node Express server and authenticating against the Instagram API via OAuth. It assumes knowledge of setting up your Node server and React Native app

Instagram meme

Introduction

Connecting to a third party service via OAuth is normally pretty straight forward as there’s examples online everywhere, but I tried to do this with the Instagram API recently and ran in to a few issues which I couldn’t easily find a solution for. This was mainly due to the changes in Instagram’s API rules at the end of 2016 - specifically the fact you can no longer add a custom deep linking URL as the redirect URI in order to obtain the Instagram access token. You’re now only allowed redirect URLs which are http:// or https://.

There’s also a slight misconception I found about using the Linking library in React Native for use with this OAuth exchange process which I’ll cover below.

To get things started you’ll need to visit the Instagram Developer site and register your app. This will give you access to a client ID and client secret codes which will be used in the React Native app.

As there’s a lot of back and forth with the server and app, I thought I’d note down the process in case it’s not clear when I’m going through the process in a little detail later.

  • User presses button on RN app
  • Request sent to Node server
  • Server uses instagram-node plugin to generate authorization URL (which contains a redirect URI)
  • Server sends authorization URL back to the app
  • App uses SafariView plugin to go to the authorization URL, which obtains a code and issues a redirect to the specified redirect URL
  • The redirect URL is our Node server, which will take the code from a URL parameter and issue another request using the instagram-node plugin to return the access_token
  • The access_token is then sent back to the app and used in future requests to the Instagram API

Server setup

First you’ll want to install the instagram-node npm package:

npm install --save instagram-node

Then set up the API end points which React Native will be calling:

const insta = require('instagram-node').instagram();

// Add client ID and secret to a config file - obtained from Instagram admin area
insta.use({
  client_id: config.insta.clientID,
  client_secret: config.insta.clientSecret
});

//redurect URI needs to be http:// or https://
var redirect_uri = 'http://localhost:1337/api/insta/getToken';

//app will send API request to this end point
router.post('/authorize_user', getAuthUrl);

//server sends back the authorization URL to the app
getAuthUrl = function(req, res) {
  res.send({
    success: true,
    url: insta.get_authorization_url(redirect_uri, { scope: ['likes'], state: 'a state' })
  })
};

//once user had entered credentials and is authorized with Instagram, the redirect URI will send the app to here
router.get('/getToken', (req, res) => {
  //the instagram-node package performs a final request to exchange the code in the redirect URI for the almighty access token
  insta.authorize_user(req.query.code, redirect_uri, function(err, result) {
    if (err) {
      console.log(err.body);
      res.send("Didn't work");
    } else {
      console.log('Yay! Access token is ' + result.access_token);
      //user is directed to the app with the access token via the URL scheme using Express redirect instead
      res.redirect(`myapp://instaAuth?token=${result.access_token}`)
    }
  });
});

You’ll notice that in most tutorials on connecting to systems like Facebook and Google via OAuth, the redirect URI is set to a deep linking URL scheme which means the info can be sent straight back to and open your app, as described in this Medium post.

As I mentioned earlier though, these URL schemes are not supported in Instagram redirect URIs recently, so my code above shows how the redirect URI directs back to the Node server to a /getToken end point and exchange for the access token there, using the server to direct the user to the myapp:// URL scheme address rather than the Instagram redirect URI.

React Native setup

I’ll quickly cover the setup in React Native so hook up a button or some event in your React Native component. I’m using Thunk with Redux so there’s a dispatch function returned inside my button onPress event:

//feed.service.js
export const authUserInstagram = () => {
  return dispatch => {
    return SocialApi.authUser().then(response => {

      //A lot of tutorials show the use of the Linking React Native library to access the authorization URL sent back from the server, but this doesn't give the best result
      //Linking.openURL(response.url).catch(err => console.error('An error occurred', err));

      //use SafariView instead
      SafariView.show({
        url: response.url,
        fromBottom: true
      })

      //listen to eventual incoming myapp:// URL scheme when access token is received by server
      Linking.addEventListener('url', handleUrl)

   }).catch(error => {
     console.log(error)
     throw error
   })
  }
}

const handleUrl = (event) => {
  //remove listener here as it makes sense rather than doing it in component
  Linking.removeEventListener('url', handleUrl)
  var url = new URL(event.url);
  const code = url.searchParams.get("token");
  const error = url.searchParams.get("error");

  //perform error handling...

  SafariView.dismiss();

}

The second and final hurdle I encountered was that most places I looked for guidance when performing the OAuth handshake suggested to use the Linking.openURL method, which does open the Safari web browser and visit the authorization URL. However when you eventually get redirected back to the myapp:// URL scheme, it asks if you’d like to open up your own app again, and has a “back to Safari” link in the top bar:

Linking openURL

The solution I found was to use a React Native plugin called react-native-safari-view. This opens a lightweight browser which closes nicely when the server redirects you back to your own app using your React Native Linking URL.

Note: Make sure you link your libraries and restart your app after installing the SafariView package.

So this covers the two main issues; the redirect URI issue with Instagram’s new API rules, and opening the browser with SafariView rather than the Linking.openURL. You can now use the access token to connect completely authenticated to the various API features. Remember, as per the Instagram dev docs it’s recommended to save the access token and have a system in place to authenticate again if the token is ever revoked or expires.

Get in touch if you’ve found a better way or want to know more!