Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error

I have been working on a side project that builds with the MERN (MongoDB, Express, React, Node) tech stack and using Passport.js, specifically Google oauth2.0. The project is deployed on Heroku (a backend application hosting cloud platform) and it is u…


This content originally appeared on DEV Community and was authored by Cindy Lam

I have been working on a side project that builds with the MERN (MongoDB, Express, React, Node) tech stack and using Passport.js, specifically Google oauth2.0. The project is deployed on Heroku (a backend application hosting cloud platform) and it is using the cloud storage database through MongoDB Atlas.

During the set up of the passport oauth2.0, I have encountered several internal server errors that has taken some time to debug. I decided to include all the possible causes of internal server error I encountered below:

Cause #1: ID & SECRET are not added to config vars

CLIENT_ID and CLIENT_SECRET: from the Google Cloud Console (should be found in the Credentials - OAuth 2.0 Client IDs - for Google Oauth API)

They are not added to the config vars in Heroku (or any other hosting platforms)

Heroku Config Vars

Cause #2: CallbackURL does not match up with the Redirect_uri

CallbackURL is the redirected url after an user is authenticated

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: "http://www.example.com/auth/google/callback"
  }, 
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ googleId: profile.id }, function (err, user) {
      return cb(err, user);
    });
  }
));

Redirect_uri is also called as Authorized redirect URIs
in the Google Cloud Console (should be found in the Credentials - OAuth 2.0 Client IDs - for Google Oauth API)

Cause #3: Routing are setup incorrectly

This is the cause that took me the longest time to debug when working on my project. Since the project is built with MERN, its frontend is using the React frontend platform, and its backend server side is using the Express Node.js web application platform.

Local Environment - the origin url is different when communicating between the frontend and the server.

Frontend url: http://localhost:3000

Backend (server) url: http://localhost:3001

  • Frontend ---> Backend

When signing in/signing out of an application, in the frontend, the route should be set up to communicate to the backend. So the route origin url should be set to http://localhost:3001, see example below:

    const handleSignInGoogle = () => {
        window.open("http://localhost:3001/auth/google", "_self");     
    }

    const handleLogOutGoogle = () => {
        window.open("http://localhost:3001/auth/logout", "_self");   
    }

The callbackURL should be set to 3001 origin url as well:

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: "http://localhost:3001/auth/google/callback"
  }, 
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ googleId: profile.id }, function (err, user) {
      return cb(err, user);
    });
  }
));
  • Frontend <--- Backend

Once the user is authenticated successfully, they would be redirected to a secret page (only authenticated users can access):

app.get("/auth/google/callback", 
  passport.authenticate("google", { failureRedirect: "/login" }),
  function(req, res) {
    // Successful authentication, redirect to secret page.
    res.redirect("http://localhost:3000/secret-page");  
  });

Once the user wants to sign out, they would be redirected to the home page:

const CLIENT_HOME_PAGE_URL = "http://localhost:3000"; 

app.get("/auth/logout", function(req, res){
    if (req.user) {
      req.session.destroy();
      req.logout();
      res.redirect(CLIENT_HOME_PAGE_URL);
    }else {
      res.send("user is already logged out!");
    }
});

~~

Live Environment - the origin url should be consistent (the same) for both the frontend and the server.

  • Frontend ---> Backend
    const handleSignInGoogle = () => {
        window.open("https://example.herokuapp.com/auth/google", "_self"); 
    }

    const handleLogOutGoogle = () => {
        window.open("https://example.herokuapp.com/auth/logout", "_self"); 
    }
passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID, 
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: "https://example.herokuapp.com/auth/google/callback",   
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
  },
   function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ googleId: profile.id }, function (err, user) {
      return cb(err, user);
    });
  }
));
  • Frontend <--- Backend
app.get("/auth/google/callback", 
  passport.authenticate("google", { failureRedirect: "/login" }),
  function(req, res) {
    // Successful authentication, redirect to secret page.
    res.redirect("/secret-page"); 
  });
const CLIENT_HOME_PAGE_URL = "https://example.herokuapp.com";

app.get("/auth/logout", function(req, res){
    if (req.user) {
      req.session.destroy();
      req.logout();
      res.redirect(CLIENT_HOME_PAGE_URL);
    }else {
      res.send("user is already logged out!");
    }
});

Cause #4: Mongo Server Error

MongoServerError: E11000 duplicate key error collection ... dup key: { username: null }

Fastest way to resolve this error is to add an additional field - username - in the User schema (where all the users login info is stored once authenticated successfully), see example below:

const userSchema = new mongoose.Schema({
  googleId: String,
  username: String,
  fullname: String,
  firstname: String,
  profileImgUrl: String  
});


passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID, 
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    // callbackURL: "https://example.herokuapp.com/auth/google/callback", //Live 
    callbackURL: "http://localhost:3001/auth/google/callback", //Local
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
  },
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({ 
      googleId: profile.id, 
      username: profile._json.email, 
      fullname: profile._json.name,
      firstname: profile._json.given_name,
      profileImgUrl: profile._json.picture
    }, function (err, user) {
      return cb(err, user);
    });
  }
));

Cause #5: Unused or Not Needed Method

This medium article (twitter oauth using passport) is one of the references I use when setting up the Google Oauth2.0 for my side project. It is extremely helpful for beginners!

This internal server error was not found while testing in the local environment until it was set live. In order to find out what causes the issue, I have used "heroku log" to find out the building process of the web application and found the issue was coming from cors method.

As found for the live environment, there isn't a need to set up cors to allow the server to accept request from different origin. In the article, cors is setup for the local environment server, without any mention regarding if it is needed in the live environment. Based on what I found from my side project, cors is not needed in the live environment.

There could be other possible causes of your internal server error that I might not have included in this blog post. Hopefully, this gives you some ideas regarding the possible causes of an internal server error when setting up the passport Google oauth2.0 authentication for your web application.


This content originally appeared on DEV Community and was authored by Cindy Lam


Print Share Comment Cite Upload Translate Updates
APA

Cindy Lam | Sciencx (2021-11-27T04:49:27+00:00) Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error. Retrieved from https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/

MLA
" » Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error." Cindy Lam | Sciencx - Saturday November 27, 2021, https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/
HARVARD
Cindy Lam | Sciencx Saturday November 27, 2021 » Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error., viewed ,<https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/>
VANCOUVER
Cindy Lam | Sciencx - » Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/
CHICAGO
" » Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error." Cindy Lam | Sciencx - Accessed . https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/
IEEE
" » Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error." Cindy Lam | Sciencx [Online]. Available: https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/. [Accessed: ]
rf:citation
» Setting up Passport.js Google OAuth2.0: Possible Causes of Internal Server Error | Cindy Lam | Sciencx | https://www.scien.cx/2021/11/27/setting-up-passport-js-google-oauth2-0-possible-causes-of-internal-server-error/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.