I'm building a MERN login system using Passport.js. I've set up all the Passport.js basics to properly run on the server-side along with the authentication middleware to protect the routes.
Since it's a MERN project I'm using React as my client-side application I need to make API calls to the backend. But I've noticed that I'm unable to get access to req.user from the backend while trying to fetch the /auth/user endpoint of my express server.
While I'm not unable the get access to req.user from neither my React application nor an API calls program such as Insomnia, I'm able to access it by manually going to the http://localhost:5000/auth/user on the browser.
SERVER:
index.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const morgan = require('morgan');
const cors = require('cors');
const passport = require('passport');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const connectDB = require('./config/db');
dotenv.config({ path: './config/config.env' });
require('./config/passport')(passport);
const app = express();
app.use(
session({
secret: 'keyboard',
resave: false,
saveUninitialized: false,
// cookie: {
// secure: true,
// },
store: new MongoStore({
mongooseConnection: mongoose.connection,
collection: 'sessions',
}),
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
app.use(express.json());
app.use(
express.urlencoded({
extended: false,
})
);
app.use(morgan('dev'));
connectDB();
app.use('/', require('./routes/index'));
app.use('/auth', require('./routes/auth'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(
`Server is running in ${process.env.NODE_ENV} mode on port ${PORT}`
);
});
config/passport.js
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const mongoose = require('mongoose');
const User = require('../models/User');
module.exports = (passport) => {
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback',
},
async (accessToken, refreshToken, profile, done) => {
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value,
};
try {
let user = await User.findOne({
googleId: profile.id,
});
if (user) {
done(null, user);
} else {
user = await User.create(newUser);
done(null, user);
}
} catch (err) {
console.error(err);
}
}
)
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
};
routes/auth.js
const express = require('express');
const passport = require('passport');
const { ensureAuth } = require('../middleware/auth');
const router = express.Router();
router.get('/google', passport.authenticate('google', { scope: ['profile'] }));
router.get(
'/google/callback',
passport.authenticate('google', {
failureRedirect: 'http://localhost:3000/login',
}),
(req, res) => {
console.log('/google/callback router:', req.user);
res.redirect('http://localhost:3000/dashboard');
}
);
router.get('/user', ensureAuth, (req, res, next) => {
if (req.user) {
res.status(200).send(req.user);
} else {
res.status(200).send({});
}
});
router.get('/logout', (req, res) => {
req.logout();
res.redirect('http://localhost:3000');
});
module.exports = router;
middleware/auth.js
module.exports = {
ensureAuth: function (req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('http://localhost:3000/login');
}
},
ensureGuest: function (req, res, next) {
if (req.isAuthenticated()) {
res.redirect('http://localhost:3000/dashboard');
} else {
return next();
}
},
};
CLIENT:
/client/src/components/page/Login.js
import React from 'react';
const Login = () => {
return (
<>
<a
style={{
border: '1px solid #0000ff',
borderRadius: '4px',
margin: '40px',
display: 'table',
padding: '5px',
fontWeight: '900',
color: '#0000ff',
textDecoration: 'none',
}}
href='http://localhost:5000/auth/google'
>
Login with Google
</a>
</>
);
};
export default Login;
/client/src/components/page/Dashboard.js
import React, { useEffect, useState } from 'react';
const Dashboard = () => {
const [userInfo, setUserInfo] = useState({});
useEffect(() => {
const fetchUserInfo = async () => {
const response = await fetch('http://localhost:5000/auth/user', {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
setUserInfo(data);
};
fetchUserInfo();
}, []);
const fetchLogout = async () => {
const response = await fetch('http://localhost:5000/auth/logout', {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
setUserInfo(data);
};
return (
<div>
<h1>Dashboard</h1>
<button
onClick={() => {
fetchLogout();
}}
>
Logout
</button>
</div>
);
};
export default Dashboard;
Any thoughts on how to get access to the req.user from the server to then proceed from there and manipulate the user data on the client-side?