node.jsexpressgoogle-oauthpassport.jsexpress-session

passportjs + googleoauth20 + express-session (valkey store optional) req.user undefined


I'm so tired i spent the whole day trying to fix it but no matter what i do it's not working all i get is undefined PLEASE PLEASE HELP!!!!

The Problem is that I'm getting req.user property as undefined after successfully authenticating the user.

I Uploaded All The code On GitHub https://github.com/Parag-47/OTX-Backend

But Here The Main Files If You Wanna Take A Looki.

Here Is MY App.js

import express from "express";
import helmet from "helmet";
import morgan from "morgan";
import mongoSanitize from "express-mongo-sanitize";
import cors from "cors";
import hpp from "hpp";
import session from "express-session";
import redisStore from "./db/valkey.js";
import auth from "./middlewares/auth.js";
import myPassport from "./services/passport.js";
import userRouter from "./routes/user.routes.js";

const cookieOptions = {
  httpOnly: true,
  secure: false, //Change To True In Production Very Important******
  //sameSite: "none" //uncomment in prod so it only accept request from one site  
};

const sessionOptions = {
  name: "sessionId",
  //store: redisStore,
  resave: false, // required: force lightweight session keep alive (touch)
  saveUninitialized: true, // false recommended: only save session when data exists
  secret: process.env.SESSION_SECRET,
  cookie: cookieOptions,
  maxAge: 1000 * 60 * 60 * 24,
}

const app = express();

//app.set("trust proxy", 1); //for proxy related issues

app.use(helmet());
app.use(
  cors({
    origin: process.env.CORS_ORIGIN,
  })
);
app.use(express.urlencoded({ extended: true, limit: "16kb" }));
app.use(express.static("public"));
app.use(session(sessionOptions));
app.use(myPassport.initialize());
app.use(myPassport.session());
app.use(myPassport.authenticate("session"));
app.use(morgan("combined"));
app.use(express.json({ limit: "16kb" }));

app.use(hpp());
app.use(mongoSanitize());

app.use("/api/v1/users", userRouter);

app.get("/", (req, res) => res.status(200).json({ Message: "Hi!" }));
app.get("/home", auth ,(req, res) =>
  res.status(200).json({ Message: "Successfully Logged In!" })
);

export default app;

Here Is My Passport.js


import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
import { User } from "../models/user.model.js";

const myPassport = new passport.Passport();

myPassport.serializeUser((user, cb)=>{
  const data = {
    id: user.id,
    displayName: user.displayName,
    name: user.name,
    emails: user.emails,
    photos: user.photos,
  };
  console.log("Got Serialized: ", user);
  cb(null, data);
});

myPassport.deserializeUser((user, cb)=>{
  console.log("Got Called: ", user);
  cb(null, user);
});

const AUTH_OPTIONS = {
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: "http://localhost:3000/api/v1/users/auth/google/callback",
  scope: ["profile"],
  session: true,
};

async function verifyCallback(accessToken, refreshToken, profile, done) {
  // console.log(accessToken);
  // console.log(refreshToken);
  //console.log("Google Profile: ", profile);
  
  try {
    const existingUser = await User.findOne({email: profile.emails[0].value});
    if(existingUser) return done(null, profile);
    const user = await User.create({name: profile.displayName, email: profile.emails[0].value});
    return done(null, profile);
  } catch (error) {
    console.error("Error: ", error);
    return done("Something Went Wrong!", profile);
  }
  
  //Create User Record And If Any Error Pass The Error To Passport Through Callback.
  //Replace Null With The Error.
}

myPassport.use(new GoogleStrategy(AUTH_OPTIONS, verifyCallback));

export default myPassport;

Here Is MY Routes.js

import { Router } from "express";
import auth from "../middlewares/auth.js";
import validateDto from "../middlewares/validateDto.middleware.js";
import validate from "../validation/jsonSchema.js";
import myPassport from "../services/passport.js";
import { register, login } from "../controllers/user.controller.js";

const userRouter = Router();

const googleAuth = myPassport.authenticate("google", {
  scope: ["email", "profile"],
});
const googleAuthCallback = myPassport.authenticate("google", {
  failureRedirect: "/login",
  successRedirect: "/home",
});

userRouter.get("/auth/google", googleAuth);
userRouter.get("/auth/google/callback", googleAuthCallback);
userRouter.post("/register", register);
userRouter.get("/login", login);

export default userRouter;

And Here The Controller.js

import { User } from "../models/user.model.js";
import asyncHandler from "../utils/asyncHandler.js";
import ApiError from "../utils/ApiError.js";
import ApiResponse from "../utils/ApiResponse.js";

const register = asyncHandler(async (req, res) => {
  if (req.isAuthenticated()) console.log("rec");
    console.log("Test: ", req.session, req.session.user, req.user, req.log, req.local);
  res.send("OK");
});

const login = asyncHandler(async (req, res) => {
  console.log(req.user);
  if (!req.isAuthenticated()) {
    throw new ApiError(400, "Login Failed Try Again!");
  }
  res.status(302).redirect("/home");
});

export { register, login };

I Tried Looking The docs and tutorials but nothing helped


Solution

  • Nobody Helped Me So I Just Implemented Google OAuth 2 From Scratch Without Using Any Libraries It was way Easier And Fun.