alesscor
alesscor

Reputation: 1163

Node.js "passport-google-oauth2" delivers "failed to fetch user profile" error in Express application

While developing the last example of a 's introductory book (an application using authentication strategy by Google OpenID), after replacing the passport-google package (which got obsolete on April 20th, 2015) with passport-google-oauth2 package (authentication strategy by Google OAuth 2.0) and having followed the indications at its documentation's page and an example here; I got the below error after selecting my Google+ account, which was thrown by the oath2.js module, concretely calling this._oauth2.get("https://www.googleapis.com/plus/v1/people/me",...) within userProfile(accessToken, done) method. The related source code and module dependencies are below.

What could be the root of the problem?

The concrete error is:

InternalOAuthError: failed to fetch user profile
    at <...>\web-app\b4\node_modules\passport-google-oauth2\lib\oauth2.js:92:28
    at passBackControl (<...>\web-app\b4\node_modules\passport-google-oauth2\node_modules\passport-oauth2\node_modules\oauth\lib\oauth2.js:124:9)
    at IncomingMessage.<anonymous> (<...>\web-app\b4\node_modules\passport-google-oauth2\node_modules\passport-oauth2\node_modules\oauth\lib\oauth2.js:143:7)
    at IncomingMessage.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)

The related application's code is:

  passport = require('passport'),
  //...
  GoogleStrategy = require('passport-google-oauth2').Strategy; // #passport-google-oauth2
  //...
  /***** #passport-google-oauth2 vv *****/
  passport.use(new GoogleStrategy({
    clientID: "a_specific_value",
    clientSecret: "another_specific_value",
    callbackURL: "http://127.0.0.1:3000/auth/google/callback",
    passReqToCallback:true
  },
  function(request, accessToken, refreshToken, profile, done) {
      profile.identifier=profile.id;
      return done(null, profile);
  }
  ));
  /***** #passport-google-oauth2 ^^ *****/
  //...
  /*****  #passport-google-oauth2 vv    *****/
  app.get('/auth/google',
  passport.authenticate('google', { successRedirect: '/',scope:
    [ 'https://www.googleapis.com/auth/userinfo.email']})
  );
  app.get( '/auth/google/callback',
    passport.authenticate( 'google', {
        successRedirect: '/',
        failureRedirect: '/'
  }));
  /*****  #passport-google-oauth2 ^^    *****/    

The application has the following dependencies:

[email protected]
├─┬ [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│   └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│   └── [email protected]
├─┬ [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ └─┬ [email protected]
│   ├── [email protected]
│   ├── [email protected]
│   └── [email protected]
├── [email protected]
├── [email protected]
└─┬ [email protected]
  ├── [email protected]
  ├── [email protected]
  ├── [email protected]
  ├─┬ [email protected]
  │ ├── [email protected]
  │ └─┬ [email protected]
  │   └── [email protected]
  ├─┬ [email protected]
  │ ├── [email protected]
  │ ├── [email protected]
  │ ├── [email protected]
  │ └── [email protected]
  ├─┬ [email protected]
  │ ├── [email protected]
  │ ├── [email protected]
  │ └── [email protected]
  ├── [email protected]
  ├── [email protected]
  ├── [email protected]
  ├── [email protected]
  ├── [email protected]
  └── [email protected]

Upvotes: 22

Views: 16742

Answers (9)

liberborn
liberborn

Reputation: 185

In my case, the error "Failed to fetch user profile" was caused by a bug in the grand-parent library node-oauth. Specifically, it was a double callback handling.

https://github.com/jaredhanson/passport-google-oauth2/issues/87

These libraries passport-google-oauth2, node-oauth are very old and not maintained well. And I didn't want to play with my own forks on GitHub. I quickly fixed it with a package patch approach.

https://dev.to/zhnedyalkow/the-easiest-way-to-patch-your-npm-package-4ece

How I applied a patch for the node-oauth library with patch-package:

  1. Install patch-package library.

  2. Patch node_modules/oauth/lib/oauth2.js with the code:

  request.on('error', function(e) {
    // `www.googleapis.com` does `ECONNRESET` just after data is received in `passBackControl`
    // this prevents the callback from being called twice, first in passBackControl and second time in here
    // see also NodeJS Stream documentation: "The 'error' event may be emitted by a Readable implementation at any time"
    if(!callbackCalled) {
      callbackCalled= true;
      callback(e);
    }
  });
  1. Run npx patch-package node-oauth.
  2. Commit the patch file to my git repository.

Upvotes: 0

sheba
sheba

Reputation: 850

This error is also thrown when logging in to an unpublished OAuth app with a user which is not in the Test Users list (under OAuth consent screen in Google's project console).

Upvotes: 0

Erfan Poursina
Erfan Poursina

Reputation: 166

When I change my package from passport-google-oauth to passport-google-oauth20, everything start to work properly.

Upvotes: 0

Pravin Suresh
Pravin Suresh

Reputation: 11

After some research, the root cause of the issue in my case was that I initially used

userProfileURL:"https://googleapis.com/oauth2/v3/userinfo" (WRONG)

instead of using

userProfileURL:"https://**www**.googleapis.com/oauth2/v3/userinfo"

Screenshot

Upvotes: 1

Raxy
Raxy

Reputation: 345

I was also facing the same issue ! Solution: Inside of
passport.use(new GoogleStrategy({ clientID: "a_specific_value", clientSecret: "another_specific_value", callbackURL: "http://127.0.0.1:3000/auth/google/callback", passReqToCallback:true, ********************************* },

On the stared line add this link "https://www.googleapis.com/oauth2/v3/userinfo" Final code will be as shown below passport.use(new GoogleStrategy({ clientID: GOOGLE_CLIENT_ID, clientSecret:.GOOGLE_CLIENT_SECRET, callbackURL: "http://localhost:3000/auth/google/secrets", passReqToCallback:true, userProfileURL:"https://www.googleapis.com/oauth2/v3/userinfo" }, This hope solves the problem !

Upvotes: -1

I found the same error and I solved it doing this:

In package.json, change "passport" value to "^0.4.0" and "passport-google-oauth" to "^2.0.0". Run "npm install" again.

Upvotes: 1

1valdis
1valdis

Reputation: 1104

I'm using Google OAuth 2.0 Playground and in my case the reason for this error was that my token has simply expired. Refreshing it in Playground resolved the issue.

Upvotes: 1

R&#233;mi Becheras
R&#233;mi Becheras

Reputation: 15222

The scope you are using is deprecated now :

passport.authenticate('google', { successRedirect: '/',scope:
  [ 'https://www.googleapis.com/auth/userinfo.email']})
);

Instead, we must use this one:

passport.authenticate('google', { successRedirect: '/',scope:
  ['email']
}));

You can also get the profile scope:

passport.authenticate('google', { successRedirect: '/',scope:
  [ 'email', 'profile' ]
}));

Upvotes: 7

alesscor
alesscor

Reputation: 1163

I just fortunately found a similar issue at jaredhanson/passport-google-oauth, which gave me the idea to go to the Google's project console and simply enable the Google+ API, which was "turned off" (oh me!!, naive developer of his first application based on Google+). That was the root of the problem. I tried again and the oauth2 started receiving profiles correctly.

Upvotes: 58

Related Questions