lsimmons lsimmons - 3 months ago 46
HTTP Question

Receive response from Instagram API call with AngularJS

To authenticate a user in an app using the Instagram API, you redirect the user to the URL

https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
.

Once the user signs in on this page, Instagram then makes a
GET
request to the redirect URI (
REDIRECT-URI
in the above URL). This call to the redirect URI contains a code which you must then include in a
POST
request to
https://api.instagram.com/oauth/access_token
to exchange for an access token which is sent in a
JSON
form in the response.

So I'm receiving the redirect call and making the request for the access token with my Express API and this works fine and I get the form with the access token.

app.get('/redirect', function(req, res){
if(req.query.error){
console.log('Error authenticating user');
console.log(req.query.error);
}
else{
request.post(
'https://api.instagram.com/oauth/access_token',
{form:{
client_id: 'my_client_id',
client_secret: 'my_client_secret',
grant_type: 'authorization_code',
redirect_uri: 'http://localhost/redirect',
code: req.query.code
}
},
function(error, response, body){
if(!error && response.statusCode == 200){
console.log(body);
//HOW DO I GET THIS RESPONSE TO ANGULAR?
res.json({
access_token: body.access_token,
full_name: body.full_name,
username: body.username,
profile_picture: body.profile_picture,
id: body.id
});
return;
}
else{
console.log(response);
console.log(body);
}
}

);
};


My question is: how to I send the access token (or error response) back to Angular?
In other words, how does Angular receive the response from a request it did not make (since the response I want to receive is from the request made with NodeJS's
request
)?

Initially I tried to make the first
GET
to
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
with Angular but I don't think this can be done because the user should be directed to the Instagram URL to sign in.




Update:

When Instagram makes the
GET /redirect?code=xxxxxx
, it sends the request to my API but also changes the page URL to
http://localhost/redirect?code=xxxxxx
. I can receive the access token in my API and send it to my client-side but because of the above URL, the page is just displayed as the text of the response and not my
index.html
with
ng-view
. How do I get the page to be my
index.html
in this situation?

I've tried with angular-router the following ways but neither worked:

.when('/redirect', {
templateUrl: 'views/success.html',
controller: 'Controller'
})


and

.when('/success', {
templateUrl: 'views/success.html',
controller: 'Controller'
})
.when('/redirect', {
redirectTo: '/success'
})

Answer

What I ended up doing (and I'm not sure this is optimal):

Once I receive the response from the call made from Node, I store the access token from the response, body.access_token, in the req.session.user object provided by the express-session npm package and then I redirect the user to the home page with res.redirect('/#/home');.

app.get('/redirect', function(req, res){
if(req.query.error){
    console.log('Error authenticating user');
    console.log(req.query.error);
}
else{
    request.post(
                 'https://api.instagram.com/oauth/access_token',
                 {form:{
                         client_id: 'my_client_id',
                             client_secret: 'my_client_secret',
                             grant_type: 'authorization_code',
                             redirect_uri: 'http://localhost/redirect',
                             code: req.query.code
                             }
                 },
                 function(error, response, body){
                     if(!error && response.statusCode == 200){
                           console.log('Success making POST to Insta API for token, making new session object');
                           console.log('token:', (JSON.parse(body).access_token), '\n');
                           req.session.user = {};
                           req.session.user.token  = JSON.parse(body).access_token;
                           req.session.save();
                           res.redirect('/#/home');
                     }
                     else{
                         console.log(error);
                         res.redirect('/#/login');
                     }
                 }

                 );
};

This way, Angular doesn't need to receive the access token after redirecting the user to Instagram's authorization page because the access token is saved in the req.session.user object which is then accessible on the backend for the duration of the session.

You can then use the access token in any requests to the Instagram API from your backend (initiated by a call to your API from Angular), e.g. by concatenating it to whatever the endpoint is for your Instagram API call like so:

var endpoint = 'https://api.instagram.com/v1/users/self/follows?access_token=' + req.session.user.token;

This method also works well with the session management functionality of express-session since a session is only created when the user can be authenticated by Instagram. See here for a quick tutorial on how to integrate session management into your app.