Session data seemingly not being sent from Express js server to Sveltekit client

everyone, so I finished building my web application and I deployed my server and frontend separately.

So the problem seems to be that my server is not sending the session data to the client (that’s what I think, I am not sure).

I am going to share parts of my code relevant to the problem.

so this is my messages/+page.svelte –

<script>
import { onMount } from 'svelte';
onMount(async () => {
        try {
            console.log('Fetching logged in user ID');
            const authResponse = await fetch('https://messenger-tu85.onrender.com/api/loggedInUserId', {
                credentials: 'include'
            });

            console.log('Auth Response:', authResponse);
            if (!authResponse.ok) {
                window.location.href = '/signin';
                return;
            }

    // other javascript code
</script>

As can be seen in the code snippet above, in my messages page, I am trying to prevent unauthenticated users from accessing the page. I do this by sending a fetch request to an endpoint on the server to determine if the user is logged in or not. This is the endpoint –

app.get('/api/loggedInUserId', async (req, res) => {
  console.log('Session:', req.session);
  console.log('User:', req.user);
  try {
    const user = await User.findById(req.user._id);
    if (!user) {
      throw new Error('User not found');
    }
    res.json({ loggedInUserId: user._id });
  } catch (error) {
    console.error('Error fetching user:', error);
    res.status(500).json({ error: 'Server Error' });
  }
});

The problem is that my application signs a user in after authentication with Google using Passport, but even after successfully logging in with Google, I cant access the messages page and the endpoint from the server prints the following out on the console –

Session: Session {
  cookie: {
    path: '/',
    _expires: 2024-07-17T15:28:12.066Z,
    originalMaxAge: 86400000,
    httpOnly: false,
    secure: true,
    sameSite: 'none'
  }
}
User: undefined
Error fetching user: TypeError: Cannot read properties of undefined (reading '_id')

This is my Passport.js, please forgive me for posting everything, I can’t figure out what part to leave out –

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

module.exports = function(passport) {
  passport.use(new GoogleStrategy({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: 'https://messenger-tu85.onrender.com/auth/google/callback',
    },
    (accessToken, refreshToken, profile, done) => {
      console.log('Google profile:', profile);

      User.findOne({ googleId: profile.id })
        .then(existingUser => {
          if (existingUser) {
            console.log('Existing user found:', existingUser);
            return done(null, existingUser);
          } else {
            const tempUser = {
              googleId: profile.id,
              email: profile.emails[0].value
            };
            console.log('Creating new temp user:', tempUser);
            return done(null, tempUser);
          }
        })
        .catch(err => {
          console.error('Error finding user:', err);
          return done(err);
        });
    }
  ));

  passport.serializeUser((user, done) => {
    console.log('Serialize user:', user);
    if (user._id) {
      done(null, user._id);
    } else {
      done(null, user);
    }
  });

  passport.deserializeUser((id, done) => {
    console.log('Deserialize user id:', id);
    if (typeof id === 'object' && id.googleId) {
      done(null, id);
    } else {
      User.findById(id)
        .then(user => {
          console.log('Deserialized user:', user);
          done(null, user);
        })
        .catch(err => {
          console.error('Error fetching user:', err);
          done(err);
        });
    }
  });
};

Now, get this, here “console.log(‘Existing user found:’, existingUser);” my server console prints out –

Existing user found: {
  _id: new ObjectId('6693d7a09886ac04b8666b2e'),
  googleId: 'prints out my google id here',
  email: 'prints out my email here',
  username: 'prints out my username i chose when i registered on my own application',
  selectedUsers: [ new ObjectId('6693da089886ac04b8666b58') ],
  __v: 0
}

Also this part “console.log(‘Serialize user:’, user);” prints out –

Serialize user: {
  _id: new ObjectId('6693d7a09886ac04b8666b2e'),
  googleId: 'my google id',
  email: 'my email',
  username: 'my username',
  selectedUsers: [ new ObjectId('6693da089886ac04b8666b58') ],
  __v: 0
}

So, based on my understanding, this serialization is meant to set the data in the session, and the fact that the logged in user’s data was serialized means that they exist in the session, right?

However, the passport.deserializeUser is never reached because the console statements there are never printed out.

This is my session.js –

const session = require('express-session');
const MongoStore = require('connect-mongo');

module.exports = (passport) => {
  return session({
    secret: process.env.SECRET,
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create({
      mongoUrl: process.env.MONGODB_URI,
      collectionName: 'sessions'
    }),
    cookie: {
      maxAge: 24 * 60 * 60 * 1000, // 1 day
      secure: process.env.NODE_ENV === 'production', // Set to true in production
      httpOnly: false,
      sameSite: 'none' // Adjust based on your cross-origin requirements
    }
  });
};

Once again, I apologize if I am making you read through lots of code, I just don’t know what parts to omit that might be the source of my problem.

This is my server.js where I suspect the problem might lie –

// imports at top of the file
dotenv.config();
const connectDB = require('./config/mongoose');
connectDB();

// Initialize Passport
const initializePassport = require('./config/passport');
initializePassport(passport);
const server = createServer(app);
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(require('./middleware/session')(passport));

app.use(cors({
  origin: 'https://svelte-of1p.onrender.com',
  credentials: true
}));

app.use(session(passport)); // does not work even if i remove this line
app.use(passport.initialize());
app.use(passport.session());

app.get('/api/loggedInUserId', async (req, res) => {
  console.log('Session:', req.session);
  console.log('User:', req.user);
  try {
    const user = await User.findById(req.user._id);
    if (!user) {
      throw new Error('User not found');
    }
    res.json({ loggedInUserId: user._id });
  } catch (error) {
    console.error('Error fetching user:', error);
    res.status(500).json({ error: 'Server Error' });
  }
});

That’s it. Hopefully my problem was well explained and someone can provide a solution.

Thanks in advance.

6

So the issue is that my client and server are deployed separately on different domains. My server handles authentication but there has to be a way to communicate with the client that a particular user is authenticated. How would the client know this?

When I sign in on the server, a session is created for the user with a unique session ID.

I put that session ID in a cookie and I send that cookie to the client –

router.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: 'https://svelte-of1p.onrender.com/signin' }),
  (req, res) => {
    if (req.user) {
      // Manually set the cookie
      res.cookie('connect.sid', req.sessionID, {
        maxAge: 24 * 60 * 60 * 1000, // 1 day
        secure: process.env.NODE_ENV === 'production', // True in production
        httpOnly: false, // Allow client-side access
        sameSite: 'None' // Allow cross-site cookies
      });
      if (req.user.username) {
        res.redirect('https://svelte-of1p.onrender.com');
      } else {
        res.redirect('https://svelte-of1p.onrender.com/select');
      }
    } else {
      res.redirect('https://svelte-of1p.onrender.com/signin');
    }
  }
);

When the client sends a request to the server, the cookie is deserialized. We extract the session ID from the cookie (remember we placed the unique session ID when creating the cookie), after extracting the session ID we then look for the user who is associated with that unique session id.

If a user exists then we know they are logged in and we can authorize them

function deserializeUser(req, res, next) {
    try {
      const cookie = req.headers.cookie;
      if (!cookie || !cookie.includes('connect.sid')) {
        return res.status(401).json({ error: 'Unauthorized' });
      }
  
      const sessionID = cookie.split('connect.sid=')[1].split(';')[0].trim();
  
      req.sessionStore.get(sessionID, (err, session) => {
        if (err || !session) {
          return res.status(500).json({ error: 'Session retrieval failed' });
        }
  
        if (!session.passport || !session.passport.user) {
          return res.status(401).json({ error: 'Unauthorized' });
        }
  
        req.user = { _id: session.passport.user }; 
  
        next();
      });
    } catch (error) {
      res.status(500).json({ error: 'Server Error' });
    }
  }
  
  module.exports = deserializeUser;
  

The above is a middleware. To then apply the middleware to all my api endpoints, in my server.js I have –

const deserializeUser = require('./middleware/deserializeUser');
app.use('/api', deserializeUser);

It always seems so simple after you spent two days debugging it 😂

See how easy it sounds but it had me frustrated.

Anyway, posting this here in case anyone sees this in the future while encountering a similar issue.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật