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 obtain access token 0 #64

Open
ThomasLai1991 opened this issue May 23, 2020 · 21 comments
Open

InternalOAuthError: Failed to obtain access token 0 #64

ThomasLai1991 opened this issue May 23, 2020 · 21 comments

Comments

@ThomasLai1991
Copy link

ThomasLai1991 commented May 23, 2020

After choosing the google account from the google page, the page redirect to my app but the process keep hanging then an error of " InternalOAuthError: Failed to obtain access token 0" was thrown, thus authentication process can not proceed.

1.launch the app
2.go to http://localhost:3000/login or http://localhost:3000/register route , both have the link to
/auth/google/ route
3. the route trigger the
passport.authenticate("google", { scope: ["https://www.googleapis.com/auth/userinfo.profile"] }));
4.redirect to the google page, then I choose my google account to login
5.the google page seems to try wait for response from local host,
6 an error of "InternalOAuthError: Failed to obtain access token 0" was thrown

I am just trying to login with google oauth2

Expected behavior

After choosing the google account from the google authentication page, I should be redirected to my app and an Access Token is retrieved from google

Actual behavior

After choosing the google account from google page, the process hanged then the error was thrown, it seems the Authoriazation Code is retrieved but the passport-google-oauth2 package faild to exchange the Access Token with the Authorization Code in hand, the package should exchange them automatically, but why is it not done?

Steps to reproduce

11.launch the app
2.go to http://localhost:3000/login or http://localhost:3000/register route , both have the link to
/auth/google/ route
3. the route trigger the
passport.authenticate("google", { scope: ["https://www.googleapis.com/auth/userinfo.profile"] }));
4.redirect to the google page, then I choose my google account to login
5.the google page seems to try wait for response from local host,
6 an error of "InternalOAuthError: Failed to obtain access token 0" was thrown

//jshint esversion:6
require("dotenv").config();
const express = require("express");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const findOrCreate = require("mongoose-findorcreate");


const app = express();

app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(
  express.urlencoded({
    extended: true
  })
);

app.use(
  session({
    secret: "Our little secret.",
    resave: false,
    saveUninitialized: false
  })
);
app.use(passport.initialize());
app.use(passport.session());

const mongoDB = "...";
const mongoDBLocal = "mongodb://localhost:27017/secretsDB";
const enviornment = process.env.NODE_ENV || "developement";
const url = enviornment === "developement" ? mongoDBLocal : mongoDB;
mongoose.set("useCreateIndex", true);
mongoose.set("useUnifiedTopology", true);
mongoose.connect(url, { useNewUrlParser: true });

const userSchema = new mongoose.Schema({
  email: String,
  password: String
  googleId: String,
  secret: String
});

userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

const User = new mongoose.model("User", userSchema);

passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.CLIENT_ID,
      clientSecret: process.env.CLIENT_SECRET,
      callbackURL: "http://localhost:3000/auth/google/secrets",
      userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
    },
    function(accessToken, refreshToken, profile, cb) {
      console.log(profile);
      
      User.findOrCreate(
        {
          googleId: profile.id
        },
        function(err, user) {
          return cb(err, user);
        }
      );
    }
  )
);

app
  .route("/")
  .get(function(req, res) {
    res.render("home");
  })
  .post(function(req, res) {});

app.route("/auth/google").get(
 passport.authenticate("google", { scope: ["https://www.googleapis.com/auth/userinfo.profile"] }));

app
  .route("/auth/google/secrets")
  .get(passport.authenticate("google", { failureRedirect: "/login" }), function(
    req,
    res
  ) {
    res.redirect("/secrets");
  });

app
  .route("/login")
  .get(function(req, res) {
    res.render("login");
  })
  .post(function(req, res) {
    const user = new User({
      username: req.body.username,
      password: req.body.password
    });
    req.login(user, function(err) {
      if (err) {
        console.log(err);
      } else {
        passport.authenticate("local")(req, res, function() {
          res.redirect("/secrets");
        });
      }
    });

    app.route("/logout").get(function(req, res) {
      req.logout();
      res.redirect("/");
    });
    const username = req.body.username;
    const password = req.body.password;
    User.findOne({ email: username }, function(err, foundUser) {
      if (err) {
        console.log(err);
      } else {
        if (foundUser) {
          bcrypt.compare(password, foundUser.password, function(err, result) {
            if (result === true) {
              res.render("secrets");
            } else {
              res.send("user not exsist or password incoreect.");
            }
          });
        }
      }
    });
  });

app.get("/secrets", function(req, res) {
  if (req.isAuthenticated()) {
    res.render("secrets");
  } else {
    res.redirect("/login");
  }
});

app
  .route("/register")
  .get(function(req, res) {
    res.render("register");
  })
  .post(function(req, res) {
    User.register({ username: req.body.username }, req.body.password, function(
      err,
      user
    ) {
      if (err) {
        console.log(err);
        res.redirect("/register");
      } else {
        passport.authenticate("local")(req, res, function() {
          res.redirect("/secrets");
        });
      }
    });
   

let port = process.env.PORT;
if (port == null || port == "") {
  port = 3000;
}
app.listen(port, function() {
  console.log(`Server online, now listening on port ${port}`);
});
// Format code using Markdown code blocks

Environment

  • Operating System: windows 7 64 x86
  • Node version: v10.16.0
  • passport version: passport 0.4.1
  • passport-google-oauth2 version:
    passport-google-oauth20@2.0.0
@toritsejuFO
Copy link

toritsejuFO commented Jun 28, 2020

I tried this out. I don't get any errors related to the whole authentication flow (InternalOAuthError in this case). I do get the user profile information back, and see it logged to the console (via console.log(profile);). Wondering why it fails for you. Can you paste the error here probably? So one can get more insight.

A few catch though, I had to fix a couple of non-trivial syntax errors, before being able to run successfully. And there was a slight issue serialising the user details here --> return cb(err, user);, but that's after the details have been fetched successfully by passport anyways...nothing to do with the whole auth flow.

@XiaohanZhong
Copy link

I have the same problem, have you fixed it?

@toritsejuFO
Copy link

Hi, If you can post the exact error for more insight.

@XiaohanZhong
Copy link

Hi, If you can post the exact error for more insight.

InternalOAuthError: Failed to obtain access token
at Strategy.OAuth2Strategy._createOAuthError (C:\Users\xhzho\Desktop\Web Development\Secretes-completed\Secrets\node_modules\passport-oauth2\lib\strategy.js:408:17)
at C:\Users\xhzho\Desktop\Web Development\Secretes-completed\Secrets\node_modules\passport-oauth2\lib\strategy.js:175:45
at C:\Users\xhzho\Desktop\Web Development\Secretes-completed\Secrets\node_modules\oauth\lib\oauth2.js:191:18
at ClientRequest. (C:\Users\xhzho\Desktop\Web Development\Secretes-completed\Secrets\node_modules\oauth\lib\oauth2.js:162:5)
at ClientRequest.emit (events.js:311:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:311:20)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21)

@toritsejuFO
Copy link

toritsejuFO commented Jul 14, 2020

Sorry for the late reply, really busy.

Ok, so I'm unable to replicate this, I really can't seem to figure out what the issue is. Everything goes smoothly.

Also, for my earlier issue where I said the user details was unable to be serialised,

And there was a slight issue serialising the user details here --> return cb(err, user)

I needed to pass the usernameField as an option for passport-local-mongoose plugin like so userSchema.plugin(passportLocalMongoose, { usernameField: 'googleId' }) ...because that's what's used by findOrCreate.

Continuing, this might be a little bit too much, but if you're up for it, you can debug the function where this fails. I was able to trace and pinpoint the exact function called for getting the accessToken, it's here, the oauth library in node_modules...that's where the actual request to google api is called over the network...

basically /path/to/project/node_modules/oauth/lib/oauth2.js [line 177]
code on that line -> exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) {

In there, you can check that you're actually getting the code passed in, and pinpoint where exactly it fails. The whole trace starts from the passport-oauth2, but the main call happens in the oauth library. Basically place debuggers or console logs everywhere and play around.

@matinzd
Copy link

matinzd commented Jan 18, 2021

I have this problem on the production:

authentication-ms | [Nest] 18   - 01/18/2021, 7:01:46 AM   [ExceptionsHandler] Failed to obtain access token +258ms
authentication-ms | InternalOAuthError: Failed to obtain access token
authentication-ms |     at GoogleStrategy.OAuth2Strategy._createOAuthError (/usr/src/app/node_modules/passport-oauth2/lib/strategy.js:408:17)
authentication-ms |     at /usr/src/app/node_modules/passport-oauth2/lib/strategy.js:175:45
authentication-ms |     at /usr/src/app/node_modules/oauth/lib/oauth2.js:191:18
authentication-ms |     at ClientRequest.<anonymous> (/usr/src/app/node_modules/oauth/lib/oauth2.js:162:5)
authentication-ms |     at ClientRequest.emit (events.js:210:5)
authentication-ms |     at TLSSocket.socketErrorListener (_http_client.js:406:9)
authentication-ms |     at TLSSocket.emit (events.js:210:5)
authentication-ms |     at emitErrorNT (internal/streams/destroy.js:92:8)
authentication-ms |     at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
authentication-ms |     at processTicksAndRejections (internal/process/task_queues.js:80:21)

No problem with localhost. Also added my domain to authorized origins and redirect urls.

@wjj28
Copy link

wjj28 commented Jan 19, 2021

Hi @XiaohanZhong ,

Check this solution posted by @danyxudong.

"I searched google a while, found a solution, and my test is ok, please check it in the below.

1st, please find your proxy on the internet explorer. My sample is http://192.168.23.4:999;

2nd, install "https-proxy-agent" node package in your project folder;

$ npm install https-proxy-agent

3rd, write the code as below;

const HttpsProxyAgent = require('https-proxy-agent');

const gStrategy = new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
);
const agent = new HttpsProxyAgent(process.env.HTTP_PROXY || "http://192.168.23.4:999");
gStrategy._oauth2.setAgent(agent);

passport.use(gStrategy);
Wish my solution works for you."

Reference:

Github: #59

NPM: https://www.npmjs.com/package/https-proxy-agent

@abanobmikaeel
Copy link

Hi @XiaohanZhong ,

Check this solution posted by @danyxudong.

"I searched google a while, found a solution, and my test is ok, please check it in the below.

1st, please find your proxy on the internet explorer. My sample is http://192.168.23.4:999;

2nd, install "https-proxy-agent" node package in your project folder;

$ npm install https-proxy-agent

3rd, write the code as below;

const HttpsProxyAgent = require('https-proxy-agent');

const gStrategy = new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
);
const agent = new HttpsProxyAgent(process.env.HTTP_PROXY || "http://192.168.23.4:999");
gStrategy._oauth2.setAgent(agent);

passport.use(gStrategy);
Wish my solution works for you."

Reference:

Github: #59

NPM: https://www.npmjs.com/package/https-proxy-agent

@wjj28 How does one "Find" their proxy on IE? Struggling with this also. Thanks in advance!

@wjj28
Copy link

wjj28 commented Feb 8, 2021

@abanobmikaeel

Internet Explorer proxy settings:

  • Open Windows Explorer.
  • Select Tools > Internet Options from the bar menu.
  • Select Connections tab.
  • Navigate to LAN settings.

@hackerunet
Copy link

I'm not sure if I'm wrong but as far as i understand, passport-google-oauth2 is not meant to deliver neither access token nor refresh token, and it has a very simple explanation.

  1. The access token returned is not the token you are looking for if you are planning to grant some api access later to the user.
  2. We need not the "access token" returned by passport, instead use the parameters returned in the redirect url configured that are in the query parameters in the final url, you will get a code parameter and a client id.
  3. Those parameters are what you need to request google for real access token and refresh token. please check https://developers.google.com/oauthplayground
  4. You could use the real google oauth 2 library to request the real access tokens inside the redirect url controller.
  5. inside the controller you should request the new tokens and return the Bearer token and the refresh token to give it to the user so he/she/xx can store it and start consuming the restful api.

So, finally the issue is not getting resolved adding openid, or email in the strategy scope, no matter what we put there apparently doesn't work because it only returns the "access token" and the user information.
So this is it, I hope this helps more users stuck in the same.

@HeyMengxu
Copy link

@wjj28 thanks for the solution, worked well for me!

@juliandm
Copy link

For me the problem was that the clientSecret was having a space in the end (copy past error). Very hard to spot since the redirects work well until the callback

@hamilton-seguin
Copy link

hamilton-seguin commented Feb 16, 2022

I have the same issue, same errors, no extra space at the end of clientSecret... I've been stuck with this for a while now..
I'm on mac using Chrome, so I can't setup a proxy as @wjj28 suggests...
Any idea how to fix this?

@iohansson
Copy link

@VoyageinStyle I had a similar issue. Found this nodejs/node#42116 issue in the node repo, downgraded to 16.3.0 and it worked like a charm without any errors.
But I guess it'll help if you're using ESM like I do and experiencing the issue.
Of course, downgrading node is not the best option, I'll investigate further when I have time.

@MithileshHinge
Copy link

MithileshHinge commented Jul 17, 2022

For anyone still struggling with this issue, there's a problem with the node-oauth package mentioned in issue #87 that causes this behaviour:
Here's a possible fix:

diff --git a/node_modules/oauth/lib/oauth2.js b/node_modules/oauth/lib/oauth2.js
index 77241c4..42dd372 100644
--- a/node_modules/oauth/lib/oauth2.js
+++ b/node_modules/oauth/lib/oauth2.js
@@ -158,6 +158,7 @@ exports.OAuth2.prototype._executeRequest= function( http_library, options, post_
     });
   });
   request.on('error', function(e) {
+    if (callbackCalled) { return }
     callbackCalled= true;
     callback(e);
   });

@RantiBaba
Copy link

@VoyageinStyle I had a similar issue. Found this nodejs/node#42116 issue in the node repo, downgraded to 16.3.0 and it worked like a charm without any errors. But I guess it'll help if you're using ESM like I do and experiencing the issue. Of course, downgrading node is not the best option, I'll investigate further when I have time.

Many thanks, this solved the issue for me. I had to downgrade to node version 16.3.0.

I'm on a Mac and using google chrome.

@patrykk21
Copy link

patrykk21 commented Nov 30, 2022

Same problem but we don't have a node-oauth dependency

@51yu
Copy link

51yu commented May 25, 2023

reproduced with

  • chrome - Incognito mode, version: 113.0.5672.126
  • firefox - privacy mode, version: 113.0.1

@ariadng
Copy link

ariadng commented Nov 26, 2023

I also experienced this exact error. In my case, the problem lied in the inability of the library to access profile data. It might be related to your internet connection, or your proxy settings.

@Chris-1912
Copy link

中国宝宝特供,哎。亲测wjj28分享的方法有效。
Make some complements based on newest development.
Thank you! @wjj28

Check this solution posted by @danyxudong.
"I searched google a while, found a solution, and my test is ok, please check it in the below.

1st, please find your proxy on the internet explorer. My sample is http://192.168.23.4:999; Add HTTP_PROXY=http://192.168.23.4:999 into the .env file in your project folder ( If there is no .env file, then create one).

2nd, install "https-proxy-agent"、“dotenv” node packages in your project folder;

$ npm install https-proxy-agent dotenv

3rd, write the code as below;

import { HttpsProxyAgent } from 'https-proxy-agent';
import dotenv from "dotenv";**

dotenv.config();

const gStrategy = new GoogleStrategy({ clientID: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, callbackURL: "http://localhost:3000/auth/google/secrets", userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo" }, function(accessToken, refreshToken, profile, cb) { console.log(profile); User.findOrCreate({ googleId: profile.id }, function (err, user) { return cb(err, user); }); } ); const agent = new HttpsProxyAgent(process.env.HTTP_PROXY || "http://192.168.23.4:999"); gStrategy._oauth2.setAgent(agent);

passport.use(gStrategy); Wish my solution works for you."

Reference:

Github: #59

NPM: https://www.npmjs.com/package/https-proxy-agent

@kightbal
Copy link

kightbal commented Apr 16, 2024

中国墙受害者特供,使用的VPN使用的不是http代理协议而是Sockets代理协议的方法,wjj28分享的方法有效。
Make some complements based on newest development.
Thank you! @wjj28

Check this solution posted by @danyxudong.
"I searched google a while, found a solution, and my test is ok, please check it in the below.

1st, please find your proxy on the internet explorer. My sample is socks5://127.0.0.1:40008; Add HTTP_PROXY=socks5://127.0.0.1:40008 into the .env file in your project folder ( If there is no .env file, then create one).

2nd, install "socks-proxy-agent"、“dotenv” node packages in your project folder;

$ npm install socks-proxy-agent dotenv

3rd, write the code as below;

import { SocksProxyAgent } from 'socks-proxy-agent';
import env from "dotenv";

env.config();

const gStrategy = new GoogleStrategy({ clientID: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, callbackURL: "http://localhost:3000/auth/google/secrets", userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo" }, function(accessToken, refreshToken, profile, cb) { console.log(profile); User.findOrCreate({ googleId: profile.id }, function (err, user) { return cb(err, user); }); } );

const Agent = new SocksProxyAgent(process.env.SOCKS5_PROXY||"socks5://127.0.0.1:40008");

gStrategy._oauth2.setAgent(Agent);

passport.use('google',gStrategy);

Wish my solution works for you."

Reference:

Github: jaredhanson/passport-oauth2#59

NPM: https://www.npmjs.com/package/socks-proxy-agent

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