Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"InternalOAuthError: Failed to fetch user profile" thrown when access_token is invalid #62

Open
ismail-khan opened this issue Oct 19, 2016 · 5 comments

Comments

@ismail-khan
Copy link

I am using passport-facebook-token to authenticate users who use a RESTful API. When I use a valid access_token, everything works fine.

However, if I delete or replace a character in my access_token and then submit an API request, then I get the following error:

InternalOAuthError: Failed to fetch user profile

This causes the server to crash. Instead of this, I want to be able to choose what error message I send back to the client, and avoid crashing the server whenever someone sends me an invalid access_token.

Here is the code to reproduce the error:

"use strict"; // Enables ES6 features

// Import modules
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
const FacebookTokenStrategy = require('passport-facebook-token');

// Constants
const PORT = process.env.PORT || 8080;

// Create app and add middleware
const app = express();
app.use(bodyParser.json());
app.use(passport.initialize());
// app.use(passport.session()); Should I use session??

// Implement (de)serializeUser methods -- Do I need this?
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));

/*
 * Set up passport strategy
 */
passport.use('facebook-token', new FacebookTokenStrategy(
    {
    clientID        : process.env.FACEBOOK_APP_ID,
    clientSecret    : process.env.FACEBOOK_SECRET
  },
  (accessToken, refreshToken, profile, done) => {

    const user = {
        'firstName' : profile.name.givenName,
      'lastName'    : profile.name.familyName,
      'id'              : profile.id,
    }

    // Perform actions against User model here

    return done(null, user); // the user object we just made gets passed to the route's controller as `req.user`
  }
));

/*
 * User is logging in
 */
app.post(
    "/login",
    passport.authenticate('facebook-token'),
    (req, res) => {

        if (req.user) {
            res.json(req.user); // Return user object
        }
        else {
            res.status(400).json({"error": "Failed to authenticate user"}); // This is never called!
        }
    }
);

/*
 * Initialize app
 */
const server = app.listen(PORT, () => {
    const port = server.address().port;
    console.log("App now running on port", port);
});
@Schnueggel
Copy link

Schnueggel commented Oct 26, 2016

Didn't test it but this could work. Just to give you an idea. This can be optimised.

app.post(
    "/login",
    (req, res) => {
      passport.authenticate('facebook-token', function (err, user, info) {
            console.error(err);
      })(req, res);
    }
);

@throbi
Copy link

throbi commented Oct 30, 2016

Hi,

I was struggling with the exact same issue, @Schnueggel's advice helped me to solve it:

app.post(
    "/login",
     (req, res) => {
          passport.authenticate('facebook-token', function (err, user, info) {
                if(err){
                    if(err.oauthError){
                        var oauthError = JSON.parse(err.oauthError.data);
                        res.send(oauthError.error.message);
                    } else {
                        res.send(err);
                    }
                } else {
                    res.send(user);
                }
          })(req, res);
        }

With this I can access meaningful information in err.oauthError.data/error.message which I can send to the client:

  • Invalid OAuth access token (for the case described by @ismail-khan)
  • Error validating access token: Session has expired on Saturday, 29-Oct-16 13:00:00 PDT. The current time is Saturday, 29-Oct-16 23:29:44 PDT.

Cheers,
Robert

@M1chaelTran
Copy link

thank you for sharing that @throbi

anyone know why i'm getting the InternalOAuthError: Failed to fetch user profile error?

@moonmidas
Copy link

Happening to me as well, I'm using this strategy with loopback.

@akapei
Copy link

akapei commented Oct 18, 2017

Add a callback to handle the error. See @mkemalsan answer here:
https://github.com/jaredhanson/passport-facebook/issues/93

My version:

router.get('/auth', passport.authenticate('facebook-token'),
    (req, res) => {
        if(req.user.err){
            res.status(401).json({
                success: false,
                message: 'Auth failed',
                error: req.user.err
            })
        }
        else if(req.user) {
            const user = {user_id: req.user.id}
            const token = jwt.sign(user, '##########', {
                expiresIn: "30d"
            })
            res.status(200).json({
                success: true,
                message: 'Enjoy your token!',
                token: token,
                user: req.user
            })
        } else {
            res.status(401).json({
                success: false,
                message: 'Auth failed'
            })
        }
    },
    // add this callback for handling errors. Then you can set responses with codes or 
    // redirects as you like.
    (error, req, res, next) => {
        if(error) {
            res.status(400).json({success: false, message: 'Auth failed', error})
        }
    }
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants