I have a React App that is calling express API which authenticates with a local strategy using Passport JS.
The client login page calls the /auth/login
route successfully. req.user
is sent back to the client, and the serialize function is called (I have a console.log that prints).
Router.post('/login', passport.authenticate('local'), (req, res) => {
res.send(req.user);
})
Subsequent requests to get user info from /auth/instructor
don't work. req.user
returns undefined and deserializeUser()
is never called.
Router.get('/instructor', (req,res)=>{
console.log(req.user)
if(req.user) res.send(req.user)
else res.send({username: "No user logged in"})
})
I believe my passport and session config is setup correctly.
const passportLocal = require('passport-local').Strategy
const bcrypt = require('bcryptjs')
const instructor = require('../Models/instructor.model')
module.exports = function(passport){
const strategy = new passportLocal( (username, password, done)=> {
console.log(username, password)
instructor
.findOne({username})
.then( instructor => {
if (!instructor) return done(null, false)
if (bcrypt.compareSync(password, instructor.password)) return done( null, instructor)
return (null, false)
})
.catch( error => console.log(error))
})
passport.use(strategy)
passport.serializeUser( (user, done)=> {
console.log('serialize', user._id)
done(null, user._id)
})
passport.deserializeUser( (id, done)=> {
console.log('de-serialize', id)
instructor.findById(id).then( instuctor => done( null, instructor))
})
}
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const cors = require('cors')
const session = require('express-session')
const passport = require('passport')
// Import routers
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
const pupilsRouter = require('./routes/pupils.routes');
const authRouter = require('./routes/auth.routes');
// Connect to database
require('./config/mongoose.config.js');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser("secret"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(session({
secret: "secret",
resave: true,
saveUninitialized: true,
cookie: {secure: false}
}))
app.use(cors({
origin: "http://localhost:3003",
credentials: true,
}))
// Initialize Passport Middleware
app.use(passport.initialize())
app.use(passport.session())
require('./config/passport.config')(passport)
// Use Routers
app.use('/api', indexRouter);
app.use('/api/users', usersRouter);
app.use('/api/pupils', pupilsRouter);
app.use('/api/auth', authRouter);
app.get('/api/ping', (req, res) => res.send("server is working"))
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
const Router = require('express').Router()
const Instructor = require('../Models/instructor.model');
const bcrypt = require('bcryptjs');
const passport = require('passport');
Router.post('/register', (req, res) => {
Instructor.findOne({username: req.body.username}).then( results => {
if (!results) {
const instructorData = {...(req.body), password: bcrypt.hashSync(req.body.password) }
Instructor.create(instructorData).then(console.log)
res.send("Instructor registered")
} else {
res.status(400).send("Instructor Already Exists")
}
} )
})
Router.post('/login', passport.authenticate('local'), (req, res) => {
res.send(req.user);
})
Router.get('/instructor', (req,res)=>{
console.log(req.user)
if(req.user) res.send(req.user)
else res.send({username: "No user logged in"})
})
module.exports = Router
This is the client code I'm trying to get to work. Clicking the profile button should get the user from the session and display the username.
import React, { useState, useEffect } from 'react'
import { NavLink} from 'react-router-dom'
import styled from 'styled-components';
import axios from 'axios'
import Logo from './Logo'
axios.defaults.withCredentials = true;
function Header() {
const [user, setUser] = useState({})
useEffect( ()=>{
axios
.get( 'http://localhost:3000/api/auth/instructor')
.then( response => setUser( response.data ))
} ,[])
const getUser = ()=> {
axios
.get( 'http://localhost:3000/api/auth/instructor')
.then( response => setUser( response.data ))
}
return (
<StyledDiv>
<Logo/>
<div className="auth">
<NavLink to="/auth/login"> Login </NavLink>
<NavLink to="/auth/register"> Register </NavLink>
<button className="profile-button" onClick={getUser}>{user.username || "Get User"}</button>
</div>
</StyledDiv>
)
}
const StyledDiv = styled.div`
width: 100vw; height: 90px;
display: grid; place-content: center;
position: relative;
box-shadow: 0px 3px 5px 5px lightgray, 0px 2px 1px 1px black;
div.auth {
position: absolute;
right: 50px; top: 35px;
a {
margin-right: 7px;
}
}
.user-profile {
background: purple;
color: white;
}
`
export default Header
Checking the network requests, the client side seems to be setting the SID cookie and making the cors request with no issue. But the req.user has no data..
Appreciate any help here, I'm going mad.