Working with Instagram API and PassportJS in a node application
Tags: node, javascript, passportjs, api
Published: 2018-02-23 12:13:25

---
title: Working with Instagram API and PassportJS in a node application
published: true
description: 
tags: Nodejs, javascript, passportjs, api
---
The usual purpose of using third party authentication, other than the fact that most users now expect it, is that you do not need to handle the registration of new users.

When they arrive at your application users can authenticate themselves with their preferred social media account, by doing so they are giving you some information about themselves which you are free to store in your database.

In this tutorial we are not going to work on storing user's information on the database, we'll just explore what kind of data we'll get from Instagram API once the user has trusted us by agreeing to authenticate.

The end result is going to look something like this

![](https://thepracticaldev.s3.amazonaws.com/i/hmjg8cdv2qinqwtxjs4r.png)

The home screen is going to include just a login button, once users login with their Instagram credentials they'll see the above page populated with their information.

## Setting up the application with Express

These are the only packages that we are going to use 

- [express](https://expressjs.com/) - The web framework we'll use 
- [pug](https://github.com/pugjs/pug) - The template engine 
- [express-session](https://github.com/konteck/express-sessions) - express middleware to create session
- [passport](http://www.passportjs.org/) - the authentication middleware
- [passport-instagram](https://github.com/jaredhanson/passport-instagram) - "Passport strategy for authenticating with Instagram using the OAuth 2.0 API."
- [axios](https://github.com/axios/axios) - HTTP client

Let's download them all: 

```
npm install --save express express-session passport passport-instagram axios pug
```

Using the `--save` flag ensures that those packages are writen in the `package.json` file. 

Let's create the basic structure for an express application. In `server.js` add the following code:

```javascript 
import express from 'express';
import session from 'express-session';
import passport from 'passport';
import Instagram from 'passport-instagram';
import axios from 'axios';
const app = express();
const port = process.env.PORT || 5656;

app.use(express.static(__dirname + '/public'));
app.set('view engine', 'pug')

app.get('/', (req,res) => {
  res.render('login')
})

app.listen(port, () => console.log(`http://localhost:${port}`))
```

That's the absolute minimum, when application runs, on the homepage (`/` route) the `views/login.pug` is rendered, the code for which looks like this.

```pug 
doctype html 
html
  head
    title=title
    link(rel='stylesheet', href='/style.css')
    meta(name='viewport' content='windth=device-width, initial-scale=1')
body 
  .wrap 
    ul.provider_login 
      li 
        a(href='/auth/instagram') Login with instagram
```

If you are new at express I'd recommend my tutorial on how to [set up a basic website with express](https://dev.to/aurelkurtula/creating-a-basic-website-with-expressjs-j92)


### Initialising passport

Passport is an authentication middleware. We have to add it as a middleware to our express application. 

```javascript 
// express-session setup 
app.use(session({
  secret: 'sytr456-65tyrd-12wrt',
  resave: true, 
  saveUninitialized: true
}))

app.use(passport.initialize());
app.use(passport.session());

passport.serializeUser((user, done) => {
  done(null, user)
})
passport.deserializeUser((user, done) => {
  done(null, user)
})
```

In the first `use()` method we set the express sessions. 

The next two lines we initialise passport. Then with `serializeUser` passport gets a response (we called it `user`) if the authentication was a success. With `done(null, user)` we are passing the entire response object into the application session. We are doing so because we are simply displaying the data that comes back from instagram. If we were using passport just to authenticate users, then we would just choose to pass the user's ID to the session `done(null, user.id)` which we'd add to a database and so on, but for us, we want everything Instagram sends back. 

`deserializeUser` then, simply removes the user information from the session (when a user logs out).

## Setting up Instagram Strategy

There are "480+ Strategies" to pick from so it's logical that each one should be installed and setup individually and passed as middleware to passport.

We've already installed `passport-instagram` so lets set it up.

```javascript
import Instagram from 'passport-instagram';
const InstagramStrategy = Instagram.Strategy; 
...
passport.use(new InstagramStrategy({
  clientID: "...",
  clientSecret: "....",
  callbackURL: "http://localhost:3000/auth/instagram/callback"
}, (accessToken, refreshToken, profile, done) => {
  done(null, profile)
}))
```

Roughly speaking, when the user clicks on "sign in with Instagram" the above code is triggered. User is directed to Instagram in order to confirm that they want to allow us access, then they are redirected to `/auth/instagram/callback`. Further, some data comes back with the approved request and `InstagramStrategy` is passing that data to passport, which in turn injects it into the session (as we already covered `passport.serializeUser((user, done) => { done(null, user) })`

#### Creating our developer (Application) `clientID` and `clientSecret`

Make sure you, as the developer, are logged into Instagram then navigate to the area for [developers](https://www.instagram.com/developer/clients/manage/) and click on "register a new client" and fill in the form.

![](https://thepracticaldev.s3.amazonaws.com/i/0pzf6a0hac96vhj0loqw.png)

**Make absolutely sure** that the website URL matches your local host, and the "redirect URI" matches what we specified as `callbackURL` above. 

After completing the registration you'll see your newly created client, you need to click on "manage" and you'll see the "Client ID" and "Client Secret" which you need to copy and paste above. 

## Configuring routes

The home route (`/`) is the login page. `/auth/instagram` will attempt to authenticate the user. `/auth/instagram/callback` is where Instagram will redirect itself when it completes authentication. `/users` is the landing page if the user is authenticated successfully.

```javascript
app.get('/', (req, res) => {
  res.render('login')
})

app.get('/auth/instagram', passport.authenticate('instagram'))
```

For the homepage we render a `login.pug` file. We call passport to attempt authentication when on `/auth/instagram`. At this point, the user is taken to the Instagram page and asked if they want to give us access. Then Instagram redirects them back to our site, at `/auth/instagram/callback`:

```javascript
 app.get('/auth/instagram/callback', passport.authenticate('instagram', {
   successRedirect: '/users',
   failure: '/'
 })) 
```

Very self explanatory, if authentication was a success we redirect the user to `/users`:

```javascript
app.use('/users', (req,res, next) => {
  if(!req.user){
    res.redirect('/')
  }
  next()
})
app.get('/users', (req, res) => {
  res.json(req.user)
})
```

To make sure the `/users` route is private, that no one without authentication has access to, we add a simple middleware whereby we check if the user (which would come from an Instagram authentication) exists, if not, we redirect to the home/login page. Else, we are rendering the entire response in the browser (**This is useful for you to see everything you get back** - I find it helpful whilst developing)

## Let's make the `/users` page look nice

Here we are going to start doing some refactoring. When a user is authenticated we are storing the entire response in the session (and therefore is available at `req.user`)

```javascript
passport.use(new InstagramStrategy({
  ...
}, (accessToken, refreshToken, profile, done) => {
  done(null, profile)
}))
```

But we do not need to store everything that comes back. Lets instead store just what we need 

```javascript
passport.use(new InstagramStrategy({
  clientID: "****",
  clientSecret: "****",
  callbackURL: "http://localhost:3000/auth/instagram/callback"
}, (accessToken, refreshToken, profile, done) => {
    let user = {};
    user.name = profile.displayName;
    user.homePage = profile._json.data.website;
    user.image = profile._json.data.profile_picture;
    user.bio = profile._json.data.bio;
    user.media = `https://api.instagram.com/v1/users/${profile.id}/media/recent/?access_token=${accessToken}&count=8`
    
    done(null, user)  
}))
```

Now we just got user's basic information. Further, in `user.media` we created the API endpoint which we'll later use to access the user's photos. Note, the API needs user's ID (which we have access through `profile.id`) and the user's access token (which we have access through `accessToken`). I also chose to limit the number of entries we'll get back to 8 entries. 

Finally, it's the `user` object that's stored in the application session.

## Creating the `/user` page

Now we are able to make a call to the Instagram API, get the 8 images back and pass them all to the `instagram.pug` template

```javascript 
app.get('/users', (req, res) => {
  axios.get(req.user.media)
  .then(function (response) {
    const data = response.data.data;
    let user = req.user;
    user.images = data.map(img => img.images);
    res.render('instagram', user)  
  })
})
```

I chose to structure the `views/instagram.pug` like so 

```pug
doctype html 
html
  head
    title=title
    link(rel='stylesheet', href='/style.css')
    meta(name='viewport' content='windth=device-width, initial-scale=1')
body 
  .wrap 
    img.cover(src=images[1].standard_resolution.url)
    .content
      h1=name
      a(href=homePage) website
      p=bio
      each image, i in images
        img.shots(src=image.thumbnail.url)  
      a(href='/logout') Logout
```

## That's it

I have added all the Node/JavaScript code to `server.js`, this is to avoid distraction and keep to the point. However you can, and should split the code which ever way it feels right to you. One way to split the code, to account for larger project is to add the routes and strategies in separate files. You can checkout the [github repository](https://github.com/aurelkurtula/Accessing-Instagram-API-with-PassportJS) to see one way of doing it