Axios then callback not working on successful Post request - node.js

Been working on figuring out user login/register with react and why my axios is not calling .then on successful post request to my api.
Server.js
//Node packages
const path = require('path');
//Required NPM Packages
const express = require('express'),
app = express(),
session = require('express-session'),
cors = require('cors'),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
MongoStore = require('connect-mongo')(session),
methodOverride = require('method-override'),
passport = require('passport'),
LocalStrategy = require('passport-local');
//MongoDB models.
const Product = require('./models/Product');
const User = require('./models/User');
//Routes.
const indexRoute = require('./routes/index');
const demoRoute = require('./routes/demos');
const blogRoutes = require('./routes/blogs');
const userRoutes = require('./routes/users');
//Port.
const PORT = 5000;
const DATABASE_URI = require('./config/database');
const mongoOptions = { useNewUrlParser:true, useUnifiedTopology:true};
//Connect to mongoDB.
mongoose.connect(DATABASE_URI, mongoOptions);
const sessionOptions = {
secret: 'somesecretword',
resave: true,
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}
//set session options
app.use(session(sessionOptions));
//Setup body-parser.
app.use(express.json());
app.use(bodyParser.urlencoded({extended:true}));
//Allow express/node to accept Cross-origin resource sharing.
app.use(cors());
app.use(express.static(path.join(__dirname, '..','client','build')));
//Setup method override.
app.use(methodOverride("_method"));
//Congifure passport.
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(function(req,res,next){
res.locals.currentUser = req.user;
next();
})
//register API routes to express.
app.use('/', indexRoute);
app.use('/demos', demoRoute);
app.use('/blogs', blogRoutes);
app.use('/users', userRoutes);
// //Register React routes to express
app.use('about', express.static(path.join(__dirname, '..','client','build')));
app.get('*', (req,res)=> {
res.sendFile(path.join(__dirname,'..','client','build','index.html'));
})
//listen to established port.
app.listen(PORT, () => {
console.log(`The server has started on port ${PORT}!`);
});
module.exports = app;
login route
router.post('/login', passport.authenticate('local'), (req, res) => {
console.log('success');
res.json({authenticated:true});
});
React front-end function
async function handleRegister(evt){
//Prevent default form redirect.
evt.preventDefault();
//Create a new user objec to pass into axios
const user = {
username: username,
password: password
}
//Send axios post request to nodeJS API.
await axios.post("http://*******/users/register", user)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
//Push react history back to index page.
}
Right now I'm using Passport.js with passport.local.mongoose Strategy and connect-mongo. When I go ahead and post to the login route with the correct users information, the callback on the back end returns success. As per the passport.authenticate method if auth is a success then we console.log and send res.json.
I've tried to use res.send, res.json, res.sendStatus but none of them seem to work. Am I missing some sort of setup with passport? As far as the documentation goes for passport-local-mongoose I shouldn't have to establish a config.
All I want to happen is that when I login I send a redirect to react and push the response route to react-router's history object via history.push(routeUrl);

I found out the problem. Was just an error on my part. Was working with the register function and not the login in function. The issue wasn't that I wasn't getting a response... Probably a queue for a break.

Related

How to config passport-jwt module? I have an error: Login sessions require session support

Hey there!
I'm starting to learn Node.js courses and in one of it the guy making a registration and authentication with MEAN stack. But his code is old and not working today with updated modules. But I fixed alot of bugs (thx to youtube comments) but when I testing http requests I still have an error:
Error: Login sessions require session support. Did you forget to use `express-session` middleware?
BUT Google says
This module lets you authenticate endpoints using a JSON web token. It is intended to be used to secure RESTful endpoints without sessions.
There is index file:
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
// Connect To Database
mongoose.connect(config.database);
// On Connection
mongoose.connection.on('connected', () => {
console.log('Connected to Database '+config.database);
});
// On Error
mongoose.connection.on('error', (err) => {
console.log('Database error '+err);
});
const app = express();
const users = require('./routes/users');
// Port Number
const port = process.env.PORT || 3030;
// CORS Middleware
app.use(cors());
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.json());
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
app.use('/users', users);
// Index Route
app.get('/', (req, res) => {
res.send('invaild endpoint');
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
// Start Server
app.listen(port, () => {
console.log('Server started on port '+port);
});

HTTP requests receive 404 in browser but work fine in Postman

I've deployed my app to Heroku and it builds fine and my React app is rendering pages correctly. However, when I try to submit a POST request to sign up a user or log a user in, I get a 404 error. I do not, however, have this problem when submitting requests from Postman. My front end is using React and Axios for submitting requests. Server is using Nodejs and Express. I was thinking it had something to do with CORS, but I've tried configuring CORS and it hasn't resolved the issue.
Front-end code for POST request:
axios.defaults.withCredentials = true;
signUp: function(userInfo) {
userInfo = {
email: userInfo.email,
password: userInfo.password,
firstName: userInfo.firstName,
lastName: userInfo.lastName,
mobileNumber: userInfo.mobileNumber
}
return axios.post('/users/signup', userInfo);
Server file
const express = require('express');
const session = require('express-session');
const passport = require('./config/passport');
const path = require("path");
const cors = require('cors');
const cookieParser = require("cookie-parser");
const app = express();
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const db = require('./models');
const sessStore = new SequelizeStore({
db: db.sequelize
});
const http = require('http').Server(app);
const routes = require('./routes');
const PORT = process.env.PORT || 3000;
const corsConfig = {
origin: "https://example.herokuapp.com/",
credentials: true
}
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
app.use(cors(corsConfig));
}
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(session({
secret: process.env.SESSION_SECRET,
name: process.env.SESSION_NAME,
store: sessStore,
resave: false,
saveUninitialized: false }));
app.use(cookieParser());
app.use(passport.initialize());
app.use(passport.session());
app.use(routes);
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname, "./client/build/index.html"));
});
db.sequelize.sync().then(() => {
http.listen(PORT, () => console.log(`Listening at http://localhost:${PORT}`));
});
Routes index file
const router = require("express").Router();
const usersRoutes = require('./users');
const isAuthenticated = require('../../config/middleware/isAuthenticated');
router.use("/users", usersRoutes);
Users Routes file
const router = require("express").Router();
const passport = require('../../config/passport');
const usersController = require("../../controllers/usersController");
router
.route('/signup')
.post(usersController.createNewUser);
router
.route('/login')
.post(passport.authenticate('local'), usersController.logUserIn);
Controller
createNewUser: function(req, res) {
db.User.create({
email: req.body.email,
password: req.body.password,
firstName: req.body.firstName,
lastName: req.body.lastName,
mobileNumber: req.body.mobileNumber
})
.then(() => res.sendStatus(200))
.catch((err) => res.send(err));
}
I resolved this. The url in the axios call was missing a piece. The reason this worked locally is because I had the proxy in React set to include the missing piece so axios calls done locally were always being sent to the right url, but they were not being sent to the right url in prod. Really relieved it was something so simple!

Express-Session generates cookies in postman but not in browsers

The issue here is when i log in with correct details, the session should be created and cookie should be generated at client side which is happening when i use postman but not in case of web browsers.
I am using the following:
passport for authenticating login details from mongoDB using mongoose
express-session for creating session when a user logs in.
cors at the backend (react is running at port 3000 and node is running at port 4000)
Here is my app.js (backend):
var createError = require('http-errors');
var cookieParser = require('cookie-parser')
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var serverRouter = require("./routes/server");
var DbRouter = require("./routes/DbRequest");
var ProductRouter = require("./routes/ProductRouter");
var CategoryRouter = require("./routes/CategoryRouter");
const session = require("express-session");
const passport = require("./passport");
var cors = require("cors");
var express = require('express');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
// USING SESSION AND PASSPORT
app.use(session({
secret: 'adsdsacoasdqwdn',
resave: false,
saveUninitialized: false,
cookie: { secure: false }
}))
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/api/admin",serverRouter);
app.use("/api/user",DbRouter);
app.use("/api/product",ProductRouter);
app.use("/api/category",CategoryRouter);
app.use(express.json({ extended:false}));
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
})
// 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;
Here is my file where i am making the routes and creating sessions :
var express = require("express");
var router = express.Router();
var connectDB = require("./connect");
const passport = require("../passport");
connectDB();
router.post("/adminlogin", (req,res,next) => {
passport.authenticate("local-adminSignin",function(err,user,info){
if(err){
return res.status(500).send(err)
}
req.login(user,function(error){
if(error){
return res.status(500).json(err)
}
return res.json(user);
})
})(req,res,next);
})
router.get("/currentAdmin", (req,res,next) => {
res.json(req.user)
})
module.exports = router;
Here , when i make a get request to "/currentAdmin" after i logged in as admin, i should be getting the user object as a response which contains all details of the admin from mongoDB.
POSTMAN LOGIN (i cant post images because this is a new account, i've linked gyazo below) :
https://gyazo.com/5569415297fbe7c7178a93634d1506e6
AFTER LOGIN, MAKING REQUEST TO "/currentAdmin"
https://gyazo.com/cd2ec99e1ee8f959d0c3874b43b76454
But, when i make same request from react, it gives me empty object as a response. One thing i noticed here is cookies are generated in postman and i get response but no cookies are there in the browser after admin login.
MY PASSPORT INDEX.JS FILE
const passport = require("passport");
const User = require("../routes/AdminSchema")
passport.serializeUser(function(user, done) {
console.log('i am serializing the user');
done(null, user.username);
});
passport.deserializeUser(function(username, done) {
console.log('i am de-serializing the user');
User.findOne({username}).lean().exec((err,user) => {
done(err, user);
});
});
//import strategy
const AdminLoginStrategy = require("./AdminLoginStrategy");
passport.use('local-adminSignin',AdminLoginStrategy);
module.exports = passport;
MY LOGIN STRATEGY FILE:
const Strategy = require("passport-local").Strategy;
const User = require("../routes/AdminSchema")
const bcrypt = require("bcryptjs")
const LoginStrategy = new Strategy({passReqToCallback:true},function(req,username,password,done){
User.findOne({username}).lean().exec((err,user) => {
if(err){
return done("db error idk bro",null)
}
if(!user){
return done("user not found!",null)
}
const isPasswordValid = bcrypt.compareSync(password, user.password);
if(!isPasswordValid){
return done("username or password not valid!",null)
}
return done(null,user)
})
})
module.exports = LoginStrategy
PS: If i send text response or other json from "/currentAdmin", I am getting it in react but i am not getting the res.user object which i think is because of cookies not being generated in the browser.
How can i solve this issue? Thanks!

Passport js local strategy is not being called

this is my app.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const app = express();
app.use(cors());
//Mongodb connection
mongoose.connect("mongodb://localhost/expressWithAngular")
.then(() => {
console.log("mongodb connected");
})
//bodyparser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//load routes
const users = require("./routes/users");
//include passport
require("./config/passport")(passport);
// use routes
app.use('/user' , users);
app.get('' ,(req,res) => {
res.send('home');
})
const port = 5000;
app.listen(port , () => {
console.log(`server is running in port ${port}`);
})
this is my user routes routes/user.js
const express = require('express');
const mongoose = require('mongoose');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
//user model init
require('./../models/User');
const User = mongoose.model('users');
router.post('/login' , (req,res,next)=>{
console.log("bodyparser" ,req.body);
passport.authenticate('local',{
session: false
},function(req,res,next){
console.log(res);
})
})
module.exports = router;
this is my config/passport.js
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const User = mongoose.model('users');
module.exports = function(passport){
passport.use(new LocalStrategy(
{
usernameField : 'email'
},
function(email,password,done){
console.log(email);
}
))
}
- i was trying to connect my mean stack app with passport
authentication, i am able to send details to backend but i couldn't
pass the value to local strategy
- I don't know where i am missing, when i consoled the local strategy is
not called, please correct me where i am missing
I believe that you have problem in your router configuration. passport.authenticate is generating middleware for you, but in your case you have wrapped it in function so you could log input parameters and you haven't returned generated middleware to router:
router.post('/login' , (req,res,next)=>{
console.log("bodyparser" ,req.body);
passport.authenticate('local',{
session: false
},function(req,res,next){
console.log(res);
})
})
I would advise you to modify your code to work like in example in official documentation:
router.post('/login' , passport.authenticate('local',{
session: false
});
)
If you really need to log req.body just add a middleware before authentication like this:
router.post('/login' , (req, res, next) {
console.log("bodyparser" ,req.body);
next();
},
passport.authenticate('local', {session: false});
)

Routes passport-local

I am trying to use passport-local to restrict access of a website.
For this I am using login_app for running passport-local, however this is in itself a route that is called from the main app.js.
While trying to route on a 2nd level (passport-files/routes) I find that my code is found, but the functions inside are not called.
This is my login_app code:
var express = require('express');
var router = express.Router();
var mongoose = require ('mongoose');
var flash = require('connect-flash');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
let app = express();
// pass passport for configuration
require('./passport-files/passport')(passport);
//For express application
app.use(morgan('dev'));
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
//Initialize passport session
app.use(session({ secret: 'secret' })); // session secret
app.use(passport.initialize());
app.use(passport.session());
app.use(flash()); // use connect-flash for flash messages stored in session
// load our routes and pass in our app and fully configured passport
require('./passport-files/routes')(app, passport);
module.exports = router;
To simplify the question I am only putting the routes.js file here:
var express = require('express');
var router = express.Router();
let app = express();
module.exports = function (app, passport) {
//function views (app, passport) {
/* GET users listing. */
// HOME PAGE (with login links) ========
app.get('/', function(req, res) {
res.render('login-welcome', {});
});
// LOGIN ===============================
// show the login form
app.get('/log-in', function(req, res) {
res.render('login', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/log-in', passport.authenticate('local-login', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/log-in', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile', {
user : req.user // get the user out of session and pass to template
});
});
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the hosme page
res.redirect('/');
};
I pretty much built this using the example from scotch.io ( https://scotch.io/tutorials/easy-node-authentication-setup-and-local ), however I cannot get it to work this way.
If i write the routes directly into login_app, they are recognized, even though the authentification still does not work.
Do any of you have an idea how to solve this? Is more information required?
This may be the problem: in your login_app module you're exporting router, however you haven't actually defined any routes on router, they're all defined on a new instance of an app.
A simple example creating a router in one file, and exporting it to use in a main app.js file, would be like this:
/** app.js */
var express = require('express');
var app = express();
var myRoutes = require('./routes');
app.use(myRoutes);
app.listen(3000);
/** routes.js */
// instaniate a new router, add routes/middleware on it, and export it
var router = require('express').Router();
// define your routes and middleware here
// router.use( ... )
module.exports = router;
Another pattern, which I think the scotch.io tutorial is using, is to have the routes file export a function into which you pass your main app instance. Then the two files would look like this:
/** app.js */
var express = require('express');
var app = express();
require('./routes')(app); // pass your main `app` instance into the function
app.listen(3000);
/** routes.js */
module.export = function(app) {
// define all your routes and middleware here directly on the `app` that gets passed in
// app.use( ... )
}

Resources