My front-end is react, and my backend is express, using passport, mongoose, express-session, and cors.
I’m able to authenticate using a passport local strategy, but the session data isn’t being sent to my browser as a cookie. When I login, the api from the backend is able to recognize the user object, as when I console log req.session, the data appears. As soon as I change routes, I’m unable to access the req.user in my backend however. I’ve tried rearranging the middleware, but I don’t seem able to get a browser cookie from my backend. They use separate ports on my localhost:
server.js:
//code needed to make express application
const express=require('express');
const app= express();
//parses anything that comes out of req.body as json
const bodyParser=require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
//required to read from .env file(env variable, holds mongo_uri and port number as process.env.PORT)
require('dotenv').config();
//connects to our mongodb using link from .env file
const mongoose= require('mongoose');
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
//our session storage, basically lets us do other things when we are logged in, rather than us being insta logged out. it uses cookies to do so
const session=require('express-session');
//our user authentication package
const passport=require('passport');
//cors is middleware, allows us to develop with server and localhost
const cors= require('cors');
app.use(cors({
origin:'http://localhost:3000',
withCredentials:true,
credentials:true,
}))
const MongoStore=require('connect-mongo')(session);
const store=new MongoStore({url:process.env.MONGO_URI});
app.use(session({
secret: process.env.SESSION_SECRET,
resave:false,
saveUninitialized:false,
secure:false,
key:'express.sid',
store:store,
}))
const cookieParser=require('cookie-parser');
app.use(cookieParser(process.env.SESSION_SECRET));
app.use(passport.initialize());
app.use(passport.session());
//the routes.js file, this is where the client gets data from
var routes=require('./routes.js');
app.use('/',routes);
require('./auth');
const PORT=process.env.PORT||5000;
app.listen(PORT,()=>{
console.log(`Server started on ${PORT}`);
});
routes.js:
const express=require('express');
var router=express.Router();
const passport=require('passport');
const bcrypt=require('bcrypt');
//our usermodel, its used to connect to mongo, and post/ update user info like registering, finding a user w/ those credentials, etc
const userModel = require('./models/userModel');
//used to create jsonwebtoken to send back to client
const jwt=require('jsonwebtoken');
const { session } = require('passport');
//register
router.post('/api/register',async (req,res)=>{
const User=await userModel.findOne({
username: req.body.username,
})
if(User){
res.json({status:"already has a user w/ that name"})
}
else{
const hashedPassword=await bcrypt.hash(req.body.password,12);
const newUser= await userModel.create({
username: req.body.username,
password: hashedPassword
})
res.json({status:"created"})
}
});
//login
router.post('/api/', async(req,res)=>{
userModel.findOne({username:req.body.username}, (err,user)=>{
if(err){
throw err;
}
if(!user){
console.log(req);
return res.json({status:"no user w/ that name"})
}
else{
bcrypt.compare(req.body.password,user.password,(error,result)=>{
if(error){
throw(error)
}
if(result){
req.session.username=req.body.username;
console.log(req.session);
const token= jwt.sign({name:user.username,},process.env.JWT_SECRET,{expiresIn:"1d"});
return res.json({status:"successful Authentication", user:user, token:token,cookie:req.session.cookie})
}
return res.json({status:"password incorrect"})
})
}
})
});
router.get('/api/profile',(req,res)=>{
return res.json({user:{
username:user.username
}})
})
module.exports=router;
auth.js:
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = process.env.JWT_SECRET;
const userModel=require('./models/userModel');
const passport=require('passport');
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
console.log("hi");
console.log(jwt_payload);
userModel.findOne({id: jwt_payload.sub}, (err, user) =>{
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
and my frontend request:
const signInUser=async(e)=>{
e.preventDefault();
const response= await fetch("http://localhost:5000/api/",{
method:'POST',
headers:{
'Content-Type':'application/json',
},
body: JSON.stringify({
username,
password
}),
})
const data= await response.json();
if (data.user){
alert('login worked');
console.log(data.token);
console.log(data);
}
else{
alert('login failed');
}
}