This is the code for the "login" process and I want to return a "token", but when I send the request I see this error, How can I solve it
in Console (with the Error):
LogIn
, NourGeorge#gmail.com
, 1923552
,✖ TypeError: Cannot read property 'hashedPassword' of undefined
, POST /user/login 401 48.376 ms - 87
I send This request from postman:
POST http://localhost:4000/user/login
Content-Type: application/json
{
"email":"NourGeorge#gmail.com",
"password":"1923552"
}
I get this answer from Postman:
{
"accessToken": null,
"message": "User login error,Invalid Information(Invalid Password)"
}
userController.js:
////Login
const login = async (req, res, next) => {
console.log('LogIn');
let { email, password } = req.body;
console.log(email)
console.log(password);
// in findUserByEmail Compaire password with password in database
const result = await User.findUserByEmail(email, password);
//if the password is correct => generate a token using JWT
if (result == 1) {
res.status(200).json({
message: 'Process succeeded'
});
// generate a token using JWT
const accessToken = jwt.sign({ id: user.uid }, process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: 3600 //1 hour
})
// res.json({accessToken:accessToken})
// return user information & access token
res.status(200).send({
id: user.uid,
email: user.email,
// password: user.password,
accessToken: accessToken
})
}
else {
res.status(401).json({
accessToken: null,
message: 'User login error,Invalid Information(Invalid Password)'
// error: 'User login error,Invalid Information(Invalid Password)'
});
}
}
userModel.js:
static async findUserByEmail(email, password) {
const Log_I=await SingletonSqlHandler.instance.sendQuery(`SELECT * FROM
GetUserByEmail('${email}')`)
.then(result => {
let userData = result.recordset[0];
const areMatched = PasswordHasher.verify(password, userData.hashedPassword);
if (areMatched) {
Printer.Logger.print("Successfully logged in", Printer.Colors.green,
Printer.Symbols.ok, true);
return 1;
} else {
Printer.Logger.print('Password is incorrect', Printer.Colors["error message"],
Printer.Symbols.err, true);
}
return 0;
}).catch(err => {
Printer.Logger.print("" + err, Printer.Colors["error message"], Printer.Symbols.err,
true);
return -1;
});
return Log_I;
}
}
userRouter.js:
const router = require('express').Router();
const userController = require('../Controllers/userController');
router.post('/login',userController.login);
module.exports = router;
app.js:
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const https=require('https');
const request=require('request');
// Modules Variable
const app = express();
// User import
const usersRoutes = require('./routes/userRoute');
const productsRoutes=require('./routes/productRoute')
app.use(express.json())
app.use(morgan('dev')); // Logger middleware
app.use(bodyParser.urlencoded({extended: false})); // Parsing body middleware
app.use(bodyParser.json({limit: '500mb'})); // Parsing JSON objects
// Adding headers
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // Allowing reqeusts from everywhere
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept,
Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});
// Detecting routes
app.use('/user', usersRoutes);
app.use('/product', productsRoutes);
// Handling invalid routes
app.use((req, res, next) => {
const error = new Error('Not found');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
module.exports = app;
Related
So I am following a tutorial on how to use JSON tokens and I am getting an error, it was working fine using sessions but I can't figure out why I am having trouble, it is the exact code
this is my authenticate.js file:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("./models/user");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const jwt = require("jsonwebtoken"); // used to create, sign, and verify tokens
const config = require("./config.js");
exports.local = passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, { expiresIn: 3600 });
}; // config.secretKey is a string of random numbers
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
console.log("JWT payload:", jwt_payload);
User.findOne({ _id: jwt_payload._id }, (err, user) => {
if (err) {
return done(err, false);
} else if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
exports.verifyUser = passport.authenticate("jwt", { session: false });
This is my app.js file (the main file):
const createError = require("http-errors");
const express = require("express");
const path = require("path");
const logger = require("morgan");
const config = require("./config");
const indexRouter = require("./routes/index");
const usersRouter = require("./routes/users");
const mongoose = require("mongoose");
const passport = require("passport");
const url = config.mongoUrl;
const connect = mongoose.connect(url, {
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser: true,
useUnifiedTopology: true,
});
connect.then(
() => console.log("Connected correctly to server"),
(err) => console.log(err)
);
const app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// app.use(cookieParser("12345-67890-09876-54321"));
app.use(passport.initialize());
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use(express.static(path.join(__dirname, "public")));
// 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;
this is the routes/users.js file (I believe the problem is here because I can sign-up (create new users) but I can't login with the same users)
const express = require("express");
const User = require("../models/user");
const passport = require("passport");
const authenticate = require("../authenticate");
const router = express.Router();
/* GET users listing. */
router.get(
"/",
function (req, res, next) {
res.send('send users')
}
);
router.post("/signup", (req, res) => {
User.register(
new User({ username: req.body.username }),
req.body.password,
(err, user) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
} else {
if (req.body.firstname) {
user.firstname = req.body.firstname;
}
if (req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save((err) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
return;
}
passport.authenticate("local")(req, res, () => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
status: "Registration Successful!",
});
});
});
}
}
);
});
// I tried to add a console.log inside of the .post() route but it never reach it
router.post(
"/login",
passport.authenticate("local"),
(req, res) => {
const token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
token: token,
status: "You are successfully logged in!",
});
}
);
router.get("/logout", (req, res, next) => {
if (req.session) {
req.session.destroy();
res.clearCookie("session-id");
res.redirect("/");
} else {
const err = new Error("You are not logged in!");
err.status = 401;
return next(err);
}
});
module.exports = router;
Basically, every time that i go to localhost:3000/users/login and send a POST request with the username and password, it tells me that I need to use express-session but I am trying to use tokens instead of session
The problem is caused when passport.authenticate('local') is called in routes/users.js file. It is a middleware that automatically calls req.login function in case correct username and password is provided.
The req.login() in turn, implements sessions in order to serialise the user in the session.
You can solve the issue by adding another parameter to passport.authenticate() as passport.authenticate('local', {session: false}. This ensures sessions are not implemented in the 'local' strategy and subsequently login can be performed.
Thanks, it helped me. You have to remove app.use(passort.session) from app.js and do
router.post('/login', passport.authenticate('local', { session: false }), (req, res) => {
var token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, token: token, status: 'You are successfully logged in!' });
});
I am following a tutorial on Udemy and creating a react app using node and express. I am losing my session and being sent back to the login page on refresh. The instructors app stays in session on refresh. Could bad routing be causing this issue? I'll provide auth.js file from my routing folder. I can add more if needed.
<<< SERVER.JS file >>>
const express = require('express');
const connectDB = require('./config/db');
const app = express();
// CONNECT To Database
connectDB();
// Init Middleware
app.use(express.json({extended: false}))
app.get('/', (req, res) => res.send('Well, hello there!'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is listening on port ${PORT}`));
<<< middleware >>>
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function(req, res, next) {
// Get token from header
const token = req.header('x-auth-token');
// Check if not token
if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' });
}
// Verify token
try {
const decoded = jwt.verify(token, config.get('jwtSecret'));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: 'Token is not valid' });
}
};
just in case my here is my auth.js file from routing folder
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const auth = require('../../middleware/auth');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../../models/User');
// #route GET api/auth
// #desc Test route
// #access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #route POST api/auth
// #desc Authenticate user & get token
// #access Public
router.post(
'/',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: 360000 },
(err, token) => {
if (err) throw err;
res.json({ token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
}
);
module.exports = router;
My app was working fine and I was able to fetch data between my Express and React servers. I reorganised my code and now i cannot get rid of the CORS errors and cannot fetch any data at all. I cannot move on with my project and simply can't figure it out for myself, I have really tried.
The front end works ok until i try to login, and then the authentication fails
I have tried adding headers and have installed CORS to my express app. I have a proxy specified in my react package.json to the express URL.
This is my Express server.js
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const cors = require('cors');
const methodOverride = require('method-override');
const db = require('./db/index.js')
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
require('dotenv').config();
const app = express();
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.use(methodOverride('_method'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cors({
origin: 'http://localhost:8080'
}));
app.use(express.static(path.join(__dirname, '../build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
const userRouter = require('./routes/user-routes')
app.use('/api', userRouter)
const fileRouter = require('./routes/file-routes')
app.use('/file', fileRouter)
// mongoose.connection.once('open', run);
app.listen(process.env.PORT || 8080);
console.log('Server is listening on port ' + process.env.PORT);
This is my user controller
const User = require('../models/Users');
const secretShh = 'mysecretsshhh';
const jwt = require('jsonwebtoken');
const home = (req, res) => {
res.send('Welcome!');
};
const secret = (req, res) => {
res.send('The password is potato');
};
const register = (req, res) => {
const { email, password } = req.body;
const user = new User({ email, password });
user.save(function(err) {
if (err) {
console.log(err);
res.status(500).send("Error registering new user please try again.");
} else {
res.status(200).send("Welcome to the club!");
}
});
};
const authenticate = (req, res) => {
const { email, password } = req.body;
User.findOne({ email }, function(err, user) {
if (err) {
console.error(err);
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!user) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
user.isCorrectPassword(password, function(err, same) {
if (err) {
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!same) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
// Issue token
const payload = { email };
const token = jwt.sign(payload, secretShh, {
expiresIn: '1h'
});
res.cookie('token', token, { httpOnly: true }).sendStatus(200);
}
});
}
});
};
const token = (req, res) => {
res.sendStatus(200);
};
module.exports = {
home,
secret,
register,
authenticate,
token
}
this is my user routes
const express = require('express')
const UserCtrl = require('../controllers/user-ctrl')
const withAuth = require('../middleware');
const router = express.Router()
router.get('/home', UserCtrl.home)
router.get('/secret', withAuth, UserCtrl.secret)
router.post('/register', UserCtrl.register)
router.post('/authenticate', UserCtrl.authenticate)
router.get('/checktoken', withAuth, UserCtrl.token)
module.exports = router
this is a middleware function to check tokens, this is where the error seems to point towards, but I'm sure its actually something to do with the proxy and fetch being blocked by CORS.
const jwt = require('jsonwebtoken');
const secret = 'mysecretsshhh';
const withAuth = (req, res, next) => {
const token =
req.body.token ||
req.query.token ||
req.headers['x-access-token'] ||
req.cookies.token;
if (!token) {
res.status(401).send('Unauthorized: No token provided');
} else {
jwt.verify(token, secret, function(err, decoded) {
if (err) {
res.status(401).send('Unauthorized: Invalid token');
} else {
req.email = decoded.email;
next();
}
});
}
}
module.exports = withAuth;
this is my auth components where the error is also pointing towards
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
//withAuth is a high-order component which takes in a component to protect
export default function withAuth(ComponentToProtect) {
return class extends Component {
constructor() {
super();
this.state = {
loading: true,
redirect: false,
};
}
async componentDidMount() {
fetch('http://localhost:8080/api/checktoken', {
credentials: 'include',
mode: 'cors'
})
.then(res => {
if (res.status === 200) {
this.setState({ loading: false });
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
this.setState({ loading: false, redirect: true });
});
}
render() {
const { loading, redirect } = this.state;
if (loading) {
return null;
}
if (redirect) {
return <Redirect to="/login" />;
}
return (
<React.Fragment>
<ComponentToProtect {...this.props} />
</React.Fragment>
);
}
}
}
login component
import React, { Component } from 'react';
export default class Login extends Component { //impplicit vs explicit returns
constructor(props) {
super(props)
this.state = {
email : '',
password: ''
};
}
handleInputChange = (event) => {
const { value, name } = event.target;
this.setState({
[name]: value
});
}
onSubmit = async (event) => {
event.preventDefault();
fetch('/api/authenticate', {
method: 'POST',
body: JSON.stringify(this.state),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.status === 200) {
this.props.history.push('/');
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
alert('Error logging in please try again');
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<h1>Login Below!</h1>
<input
type="email"
name="email"
placeholder="Enter email"
value={this.state.username}
onChange={this.handleInputChange}
required
/>
<input
type="password"
name="password"
placeholder="Enter password"
value={this.state.password}
onChange={this.handleInputChange}
required
/>
<input type="submit" value="Submit"/>
</form>
);
}
}
This is the main error:
Access to fetch at 'http://localhost:8080/api/checktoken' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8080' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
It also says:
withAuth.jsx:17 GET http://localhost:8080/api/checktoken net::ERR_ABORTED 401 (Unauthorized)
In my express app the terminal says it cant read the token in the middleware, I presume its also due to cors :
TypeError: Cannot read property 'token' of undefined
at withAuth (/Users/nancycollins/virtuload-beta/backend/middleware.js:6:16)
Apologies if this is too much information I've just been stuck on this for too long and really dont know what else to do.
Update:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
With:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
I encourage you to do app.use(cors()); before those lines
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
...
Express stacks those functions lets say as a "array" and because of that the order matters
Hope it resolve your problem.
Bit late to the party but just going to leave my answer here incase someone else has the same problem.
The idea is to allow CORS request to your Express server. Go to the directory with your server.js file and run:
npm install cors
Then inside server.js add the following lines:
const cors = require('cors');
app.use(cors());
I am using JWT to generate a token for access control. I can hit /api/auth/login and get back the token, however, when attempting to hit /api/protected with a GET request, I get 401 Unauthorized.
I've looked through SO and haven't found anything specific although it seems like a routine issue, maybe. I have tried moving the route around in the server.js file to see if that is the issue . I have removed the preceeding slash from the route (from /api/protected to api/protected) and using the latter I get back a bunch of html due to, I think, the app.use(express.static....
I am using Postman to test it but i'm not sure what I'm missing here. I have also made sure to set the authorization to Bearer Token in Postman.
'use strict';
const { Strategy: LocalStrategy } = require('passport-local');
// Assigns the Strategy export to the name JwtStrategy using object destructuring
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
const { User } = require('../users/models');
const { JWT_SECRET } = require('../config');
const localStrategy = new LocalStrategy((username, password, callback) => {
let user;
User.findOne({ username })
.then(_user => {
user = _user;
if (!user) {
// Return a rejected promise so we break out of the chain of .thens.
// Any errors like this will be handled in the catch block.
return Promise.reject({
reason: 'LoginError',
message: 'Incorrect username or password'
});
}
return user.validatePassword(password);
})
.then(isValid => {
if (!isValid) {
return Promise.reject({
reason: 'LoginError',
message: 'Incorrect username or password'
});
}
return callback(null, user);
})
.catch(err => {
if (err.reason === 'LoginError') {
return callback(null, false, err);
}
return callback(err, false);
});
});
const jwtStrategy = new JwtStrategy(
{
secretOrKey: JWT_SECRET,
// Look for the JWT as a Bearer auth header
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
// Only allow HS256 tokens - the same as the ones we issue
algorithms: ['HS256']
},
(payload, done) => {
done(null, payload.user);
}
);
module.exports = { localStrategy, jwtStrategy };
'use strict';
//How does order of code affect how it works?
// YES
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const morgan = require('morgan');
const passport = require('passport');
const path = require('path');
const { router: usersRouter } = require('./users');
const { router: authRouter, localStrategy, jwtStrategy } = require('./auth');
mongoose.Promise = global.Promise;
// Is this needed if dotenv is in this file also?
const { PORT, DATABASE_URL } = require('./config');
const app = express();
// Logging
app.use(morgan("common"));
// const logRequest = (req, res, next) => {
// const now = new Date();
// console.log(
// `local log - ${now.toLocaleDateString()} ${now.toLocaleTimeString()} ${req.method} ${req.url}`
// );
// next();
// }
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE');
if (req.method === 'OPTIONS') {
return res.send(204);
}
next();
});
passport.use(localStrategy);
passport.use(jwtStrategy);
//app.use(logRequest);
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/api/users/', usersRouter);
app.use('/api/auth/', authRouter);
app.use("/api/items", require('./routes/api/items'));
// protected route that needs a valid JWT for access
const jwtAuth = passport.authenticate("jwt", { session: false });
// route to handle static content ie.e *.jpg
app.use(express.static(path.join(__dirname, "client", "build")));
app.get('/api/protected', jwtAuth, (req, res) => {
return res.json({
data: 'Hello World'
});
});
// have react client handle all additional routes
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
let server;
function runServer(DATABASE_URL, port = PORT) {
return new Promise((resolve, reject) => {
// How is DATABASE_URL used? What is the value? Is it referencing
// DATABASE_URL?
mongoose.connect(DATABASE_URL, { useNewUrlParser: true, useFindAndModify: false }, (err) => {
console.log("Success");
if (err) {
return reject(err);
}
server = app.listen(port, () => {
console.log(`Your app is listening on port ${PORT}`);
resolve();
})
.on('error', (err) => {
mongoose.disconnect();
reject(err);
});
});
});
}
function closeServer() {
return mongoose.disconnect()
.then(() => new Promise((resolve, reject) => {
console.log("Closing server");
server.close((err) => {
if (err) {
return reject(err);
}
resolve();
});
}));
}
if (require.main === module) {
runServer(DATABASE_URL)
.catch(err => console.error(err));
}
module.exports = { app, runServer, closeServer };
enter code hereI am expecting to get back a string that says "Hello World" just to make sure i'm hitting the endpoint correctly. Instead I get the 401 error, GET /api/protected HTTP/1.1" 401enter code here
I am having trouble accessing already saved in MongoStore session. In short the algorithm is: client(http://localhost:8080) sends POST request to the server (http://localhost:3000/); the program successfully creates session, registers/logins user and after that redirects to client (http://localhost:8080/finish-registration) and that page in turn makes another POST request (http://localhost:3000/s) which tries to retrieve session, but it is unavailable as
router.post('/s', function(req, res) {
console.log('ID in POST: ', req.session.userId);
});
returns undefined.
Below is my server setup. For the backend I use expressjs, express-session, mongostore, frontend: React with axios to send requests. Does anyone know where I am doing a mistake? thanks
server.js:
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const routes = require('./routes/router');
// connect to MongoDB
mongoose.connect('mongodb://localhost/testForAuth');
const db = mongoose.connection;
// handle mongo error
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', () => {
console.log('we are connected');
});
// use sessions for tracking logins
app.use(
session({
secret: 'work_hard',
resave: true,
saveUninitialized: true,
store: new MongoStore({
mongooseConnection: db
})
})
);
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
// parse incoming requests
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// serve static files from template
app.use(express.static(__dirname + ''));
// include routes
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
const err = new Error('File not found');
err.status = 400;
next(err);
});
// error handler
// define as the last app.use callback
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.send(err.message);
});
// listen on port 3000
app.listen(3000, () => {
console.log('Express app listening on port 3000');
});
routes/router.js:
const express = require('express');
const router = express();
const cors = require('cors');
const fs = require('fs');
const User = require('../models/user.js');
// POST route for updating data
router.post('/', function(req, res, next) {
if (req.body.email && req.body.password && req.body.confirmPassword) {
if (req.body.password !== req.body.confirmPassword) {
var err = new Error('Passwords do not match');
err.status = 400;
res.send('Passwords do not match');
return next(err);
} else {
console.log(req.body.email, req.body.password);
var userData = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
registrationFinished: false
};
User.create(userData, function(error, user) {
if (error) {
console.log("COULDN't create user");
return next(error);
} else {
console.log('ADDED NEW USER');
req.session.userId = user._id;
return res.redirect('/profile');
}
});
}
} else if (req.body.email && req.body.password) {
User.authenticate(req.body.email, req.body.password, function(error, user) {
if (error || !user) {
var err = new Error('Wrong email or password');
err.status = 401;
return next(err);
} else {
console.log('LOGIN!!!');
req.session.userId = user._id;
return res.redirect('/profile');
}
});
} else {
var err = new Error('All fields required');
err.status = 400;
return next(err);
}
});
router.post('/s', function(req, res) {
console.log('ID in POST: ', req.session.userId);
});
router.get('/s', function(req, res) {
console.log(req.session.userId);
return res.redirect('http://localhost:8080/finish-registration');
});
// GET route after registering
router.get('/profile', function(req, res, next) {
console.log(`Find by id: `, req.session.userId);
User.findById(req.session.userId).exec(function(error, user) {
if (error) {
return next(error);
} else {
if (user === null) {
var error = new Error('Not authorized! Go back!');
error.status = 400;
return next(error);
} else {
console.log('Client username check: ' + req.session.userId);
return res.redirect('http://localhost:8080/finish-registration');
}
}
});
});
// GET for logout logout
router.get('/logout', function(req, res, next) {
if (req.session) {
// delete session object
req.session.destroy(function(err) {
if (err) {
return next(err);
} else {
return res.redirect('/');
}
});
}
});
module.exports = router;
models/user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
var UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
trim: true
},
password: {
type: String,
required: true
},
confirmPassword: {
type: String,
required: true
},
registrationFinished: {
type: Boolean,
required: false
}
});
// authenticate input against database
UserSchema.statics.authenticate = function(email, password, callback) {
User.findOne({ email: email }).exec(function(err, user) {
if (err) {
return callback(err);
} else if (!user) {
var err = new Error('User not found');
err.status = 400;
return callback(err);
}
bcrypt.compare(password, user.password, function(err, result) {
if (result === true) {
return callback(null, user);
} else {
return callback();
}
});
});
};
// hashing a password before saving it to the database
UserSchema.pre('save', function(next) {
var user = this;
console.log(user.email);
bcrypt.hash(user.password, 10, function(err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
var User = mongoose.model('User', UserSchema);
module.exports = User;
If anyone faces the same issue, the problem was related to axios. Adding
axios.defaults.withCredentials = true;
did the trick. Also note, that adding withCredentials: true as an option to post request did not help, i.e. this does not work:
axios
.post('http://localhost:3000/s', {
newUserInfo: jsonData,
withCredentials: true
})