0

I'm working on a MERN stack project and I'm facing this issue where my req object is not being persistent and holding the req.user after it has been authenticated. when the /google/callback enpoint is triggered the req.user seems to exist but the second my application tries to fetch /user the req.user is undefined

I've tried almost everything by now, I've checked my .env variables and I've set up a proper Session storage as well, but this thing just isn't working on production , on local development environment it's working absolutely fine.

googleStrategy.js

const User = require('../models/User')
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20').Strategy

passport.use(
    new GoogleStrategy(
        {
            clientID: process.env.CLIENT_ID,
            clientSecret: process.env.CLIENT_SECRET,
            callbackURL: process.env.CALLBACK_URL,
            passReqToCallback: true,
        },
        async function (request, accessToken, refreshToken, profile, done) {
            try {
                // get the returned data from profile
                let data = profile?._json
                console.log(data)
                let user = await User.findOne({ email: data.email })
                if (!user) {
                    // create user, if user does not exist
                    const newUser = await User.create({
                        email: data.email,
                        googleId: data.id,
                        firstName: data.given_name,
                        lastName: data.family_name,
                        displayName: `${data.given_name} ${data.family_name}`,
                        photos: profile.photos.map((photo) => photo.value),
                    })
                    return await done(null, newUser)
                }
                return await done(null, user)
            } catch (error) {
                return done(error, false)
            }
        }
    )
)

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

passport.deserializeUser(async (id, done) => {
    try {
        const user = await User.findById(id)
        done(null, user) // Deserialize user from the id
    } catch (error) {
        done(error, null)
    }
})

auth.js

const express = require('express')
const router = express.Router()
const passport = require('passport')
const { Bookmark, Like } = require('../models/BlogStats')
const Profile = require('../models/Profile')
const { userAuthenticated } = require('../middleware/checkAuth')

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

router.get(
    '/google/callback',
    passport.authenticate('google', {
        failureRedirect: process.env.CLIENT_URL,
        failureMessage: true,
    }),
    async (req, res) => {
        console.log('User authenticated:', req.user, 'Session:', req.session, 'isAuthenticated:', req.isAuthenticated())
        await Bookmark.findOrCreate({ userId: req.user._id })
        await Like.findOrCreate({ userId: req.user._id })
        await Profile.findOrCreate({ userId: req.user._id })
        res.redirect(`${process.env.CLIENT_URL}/home`)
    }
)

router.get('/logout', (req, res) => {
    req.logout((err) => {
        if (err) res.sendStatus(500)
        else {
            res.clearCookie('connect.sid', { path: '/' })
            res.json({ logout: 'successful' })
        }
    })
})

router.get(
    '/user',
    (req, res, next) => {
        console.log(req.user, req.session, req.isAuthenticated())
        if (req.isAuthenticated()) next()
        else res.json({ error: 'unauthorized', loggedIn: false })
    },
    (req, res) => {
        const user = {
            ...req.user,
            loggedIn: true,
        }
        res.status(200).json(user)
    }
)

module.exports = router

server.js

require('dotenv').config()

const express = require('express')
const mongoose = require('mongoose')
const connectDB = require('./config/dbConfig')
const session = require('express-session')
const MongoStore = require('connect-mongo')
const passport = require('passport')
const cors = require('cors')
const path = require('path')

const authRouter = require('./routes/auth')
const apiRouter = require('./routes/api')


const app = express()
connectDB()

app.use(
    cors({
        origin: process.env.CLIENT_URL,
        credentials: true,
    })
)

app.use(express.static(path.join(__dirname, 'public')))
app.use(express.json({ limit: '10mb' }))
app.use(express.urlencoded({ limit: '10mb', extended: false }))
app.use(
    session({
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: false,
        cookie: { httpOnly: true, secure: process.env.NODE_ENV === 'Production', maxAge: 24 * 60 * 60 * 1000 },
        store: MongoStore.create({ mongoUrl: process.env.MONGO_URI, collectionName: 'sessions' }),
    })
)
console.log(process.env.NODE_ENV, process.env.NODE_ENV === 'Production')
app.use(passport.initialize())
app.use(passport.session())

require('./config/googleStrategy')

app.use('/auth', authRouter)
app.use('/api', apiRouter)

const PORT = process.env.PORT || 3000
mongoose.connection.once('open', () => {
    console.log('Connected to MongoDB')
    app.listen(PORT, () => {
        console.log(`Server running on port ${PORT}`)
    })
})

EDIT

I have pinned down the issue, it seems that the connect.sid is not being sent to the client , idk why but on local dev environment it works but on production it seems to just forget it, I'm able to store sessions on each authentication but not able to send the cookie to client.

1
  • "...not able to send the cookie to client." Can you please show the fetch executed from the client. Commented Jun 18 at 10:10

0

Browse other questions tagged or ask your own question.