Search code examples
node.jsmongodbpassport-google-oauth

how to use passport-google-oauth20 twice in the same app


I'm trying to use the passport-google-oauth20 twice in my node app but it's not working. Still learning passport authentication.

So here's the problem:

i made a button for the user to login using google(/auth.google) and a button for a user to register using google(/users/google). I want it so that if the user is already registered on my app using google and he goes on a presses "register using google" button, he should be redirected back to the register page(auth fails). In my case when i add the strategy once and add a login button only(without register), auth works and users is redirected to dashboard. However, when i add the strategy again in passport.js and the 'already registered user" tries to login using google, he gets redirected to register page(where the register using google button is found) instead of dashboard. I know there's no need to do such thing and no need to use the same strat again for registeration as it works the same for logging in. just wondering if it's possible to work.

Here's my code:

Passport.js

const GoogleStrategy = require("passport-google-oauth20").Strategy;

const myClientId = require("./keys").clientID;
const myClientSecret = require("./keys").clientSecret;

// get the user schema
const User = require("../models/User");

// passport google authentication
module.exports = function (passport) {
  passport.use(
    new GoogleStrategy(
      {
        clientID: myClientId,
        clientSecret: myClientSecret,
        callbackURL: "/auth/google/callback",
      },
      (accessToken, refreshToken, profile, done) => {
        const newUser = new User({
          googleId: profile.id,
          displayName: profile.displayName,
          firstName: profile.name.givenName,
          lastName: profile.name.familyName,
          image: profile.photos[0].value,
        });

        User.findOne({ googleId: profile.id })
          .then((user) => {
            if (user) {
              done(null, user);
            } else {
              newUser.save().then((userd) => {
                done(null, userd);
              });
            }
          })
          .catch((err) => console.log(err));
      }
    )
  );

// using same strategy again but different callback URL

  passport.use(
    new GoogleStrategy(
      {
        clientID: myClientId,
        clientSecret: myClientSecret,
        callbackURL: "/users/google/callback",
      },
      (accessToken, refreshToken, profile, done) => {
        const newUser = new User({
          googleId: profile.id,
          displayName: profile.displayName,
          firstName: profile.name.givenName,
          lastName: profile.name.familyName,
          image: profile.photos[0].value,
        });

        User.findOne({ googleId: profile.id })
          .then((user) => {
            if (user) {
              done(null, false);
            } else {
              newUser.save().then((userd) => {
                done(null, userd);
              });
            }
          })
          .catch((err) => console.log(err));
      }
    )
  );

  passport.serializeUser((user, done) => {
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    User.findById(id, (err, user) => {
      done(err, user);
    });
  });
};

app.js

/* initalized passport, session and other stuff here but just showing you the routes and the passport 
function in app.js */

require("./config/passport")(passport);

app.use("/auth", require("./routes/auth"));
app.use("/users", require("./routes/users"));

auth.js

const express = require("express");
const passport = require("passport");
const router = express.Router();

//? register and login handle
router.get(
  "/google",
  passport.authenticate("google", {
    scope: ["profile"],
  })
);

//? google auth callback
router.get(
  "/google/callback",
  passport.authenticate("google", {
    successRedirect: "/dashboard",
    failureRedirect: "/",
  })
);

module.exports = router;

users.js

const express = require("express");
const router = express.Router();
const passport = require("passport");
const { ensureAuthenticated, forwardAuth } = require("../config/checkAuth");

//? register page
router.get("/register", forwardAuth, (req, res) => {
  res.render("register");
});

//? login page
router.get("/login", forwardAuth, (req, res) => {
  res.render("login");
});

//? logout handle
router.get("/logout", (req, res) => {
  req.logOut();
  res.redirect("/");
});

router.get(
  "/google",
  passport.authenticate("google", {
    scope: ["profile"],
  })
);

router.get(
  "/google/callback",
  passport.authenticate("google", {
    successRedirect: "/dashboard",
    failureRedirect: "/users/register",
  })
);

module.exports = router;

So if the users logs in on /auth/google ...he gets redirected to the register page(/users/register)! Can't know why


Solution

  • I solved my problem.

    the solution was actually simple. Just using the same passport.js file.

    in passport.js

    const GoogleStrategy = require("passport-google-oauth20").Strategy;
    
    module.exports = function (passport) {
    
      passport.use("firstUse", new GoogleStrategy(....))
      passport.use("secondUse", new GoogleStrategy(...))
    }
    
    

    so the thing is that you can register the strategy with any name you want and then when you want to handle the authorization middleware in the routes you just do this:

    in users and auth.js

    app.get("/auth/google/callback", passport.authenticate("firstUse"));
    app.get("/users/google/callback", passport.authenticate("secondUse"));
    
    

    just add the name that you registered with. I thought that it is necessary to only use passport.authenticate("google") and not any name else than "google".