Unauthorized 401 Error Even When User Being Signed In - Passport-Google-OAuth2

57 Views Asked by At

I was trying to implement Passport-google-Oauth2 authentication with react, But i consistently face an Unauthorized 401 error when the user tries to sign in using google and they will be kicked back to the "/login" page. This issue arises even when the user is successfully logged in through google and their details are securely stored to a mongoose database.

The issue didn't occur when I was working on localhost, but now that I've deployed both the client and server sides to Vercel and Render respectively, it has been occurring.

The following is the server side(app.js) code:

After these processes:

  • Creating a secret session
  • Initializing Passport
  • Serializing/deserializing
  • Using the Google strategy

I create routes to:

  • Handle Google authentication
  • Handle successful and failed authentication redirects to the specified routes shown in the code
  • Check if the user is signed in; if so, send them a successful 200 message; if not, send a failure 401 unauthorized message.
const express = require("express");
const app = express();
const cors = require("cors");
const passport = require("passport");
require("dotenv").config();
const mongoose = require("mongoose");
const session = require("express-session");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const findOrCreate = require("mongoose-findorcreate");
const mongodbConnectionString = process.env.MONGODB_URI;
const opts = {};

// use and initializing express, express-session and passport modules
app.use(
  express.urlencoded({
    extended: true,
  })
);

app.use(express.json());
app.use(
  cors({
    credentials: true,
    origin: "https://netflix-app-clonee.vercel.app",
  })
);
app.use(
  session({
    secret: "Our big secret!",
    resave: false,
    saveUninitialized: true,
  })
);

app.use(passport.initialize());
app.use(passport.session());

// connecting to mongodb server
main().catch((err) => console.log(err));

async function main() {
  await mongoose.connect(mongodbConnectionString);
}

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

// pluging in the passort-local-mongoose module
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

// DB Model
const User = mongoose.model("User", userSchema);

// let passport use our cookies by serializing and deserialising
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

// Google strategy usage 
passport.use(
  "google",
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: "https://netflix-api-6lk8.onrender.com/auth-netflix-account",
      userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo",
    },
    function (accessToken, refreshToken, profile, cb) {
      User.findOrCreate(
        { googleId: profile.id, username: profile.displayName },
        function (err, user) {
          return cb(err, user);
        }
      );
    }
  )
);

// Creating Routes
app.get(
  "/auth/google",
  passport.authenticate("google", {
    scope: ["profile"],
  })
);

app.get(
  "/auth-netflix-account",
  passport.authenticate("google", {
    failureRedirect: "https://netflix-app-clonee.vercel.app/login",
    successRedirect:
      "https://netflix-app-clonee.vercel.app/auth-netflix-account",
  })
);

app.get('/protected', (req, res) => {
  if (req.user) {
    res.status(200).json({ message: 'You are protected!' });
  } else {
    res.status(401).json({ message: 'User is Unauthorized' });
  }
});


app.delete("/delete-movie-list", async (req, res) => {
  try {
    await MovieList.deleteMany();
  } catch (error) {
    console.error("Error deleting item:", error);
    res.status(500).json({ message: "Internal server error" });
  }
});

app.get("/user-movie-list", async (req, res) => {
  try {
    const movieInfo = await MovieList.find();

    res.status(200).json(movieInfo);
  } catch (error) {
    console.error("Error:", error.message);
    res.status(500).json({ error: "Internal Server Error" });
  }
})

app.listen(3001, () => console.log("Listening to port 3001"));

This is the client side code:

Here, I first fetch the /protected route from the server and check if the user is authenticated or logged in. If they are authenticated, setUsername(res.data.user.username);. If not, I navigate them to the "/login" route.

import { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import UserAccount from "./UserAccount";

export default function AuthUsersAcoount() {
  const [username, setUsername] = useState("")
  const navigate = useNavigate();
  useEffect(() => {
    axios
      .get("https://netflix-api-6lk8.onrender.com/protected", { withCredentials: true })
      .then((res) => {
        if (res.status === 200) {
          setUsername(res.data.user.username);
        } else { 
          navigate("/login");
        } 
      })
      .catch((error) => {  
        navigate("/login");
        console.log(`the error is an internal server `);
      });
  }, []);
  return (
    <div>
      <UserAccount username={username} />
    </div>
  );
}

This is the error i get:

Unauthorized 401 error(click me to see the error

To solve the issue, i used req.isAuthenticated() instead of req.user but it didn't work:

app.get('/protected', (req, res) => {
  if (req.isAuthenticated()) {
    res.status(200).json({ message: 'You are protected!' });
  } else {
    res.status(401).json({ message: 'User is Unauthorized' });
  }
});
0

There are 0 best solutions below