Express new session on a request from frontend app - node.js

I am creating a login page, and the problem is that express creating a new session each time a request comes from the frontend app. I have checked and tried all the other answers on the net and here at SO. The part that bugs me most is that it works with curl, but not via the frontend app.
Here is the code:
server.js
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require('express-session')
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cors());
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({extended: true})); // for parsing application/x-www-form-urlencoded
app.use(cookieParser('keyboard cat'));
app.set('trust proxy', true);
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
httpOnly: true,
cookie: {secure: false}
}));
app.get('/secured', function (req, res) {
res.header("Access-Control-Allow-Origin", "http://localhost:3006");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cookie");
if (req.session) {
console.log("has session", req.session);
if (req.session.loggedInUser) {
res.status(200).end("OK");
} else {
res.status(401).end("NOTOK1");
}
} else {
res.status(401).end("NOTOK2");
}
});
const users = [
{email: 'foo#bar.com', pass: 'foo'}
];
app.post('/login', function (req, res) {
const matched = users.filter(e => e.email === req.body.loginEmail && e.pass === req.body.loginPassword);
if (matched === undefined || matched.length === 0) {
res.status(401).end('NOTOK');
} else {
req.session.loggedInUser = matched[0];
req.session.save();
res.status(200).end('OK');
}
});
app.listen(8000, () => {
console.log('Started, listening');
});
And the login component from the frontend (React).
import React from "react";
import {MDBBtn, MDBCol, MDBContainer, MDBRow} from 'mdbreact';
import axios from 'axios';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {error:{}};
this.handleLogin = this.handleLogin.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleLogin(event) {
event.preventDefault();
let state = this.state;
let registerFormInputs = Object.keys(this.state).filter(v => v.startsWith("login"));
const data = {};
registerFormInputs.forEach(function (input) {
data[input] = state[input];
});
axios.post('http://localhost:8000/login', data)
.then(function (response) {
axios.get('http://localhost:8000/secured', {withCredentials: true})
.then(resp => {
console.log(resp);
});
})
.catch(err => {
this.setState({error: err.response})
})
}
handleChange(event) {
this.setState({[event.target.id]: event.target.value});
}
render() {
return (
<MDBContainer>
<MDBRow>
<MDBCol md="6">
<form onSubmit={this.handleLogin}>
<p className="h4 text-center mb-4">Log in</p>
{this.state.error.data ? <div>{this.state.error.data}</div> : null}
<label htmlFor="loginEmail" className="grey-text">
Email
</label>
<input
type="email"
id="loginEmail"
className="form-control"
onChange={this.handleChange}
/>
<br/>
<label htmlFor="loginPassword" className="grey-text">
Password
</label>
<input
type="password"
id="loginPassword"
className="form-control"
onChange={this.handleChange}
/>
<div className="text-center mt-4">
<MDBBtn color="indigo" type="submit">Login</MDBBtn>
</div>
</form>
</MDBCol>
</MDBRow>
</MDBContainer>
);
}
}
export default Login;
The frontend:
https://codesandbox.io/s/2vor7xproj
The backend:
https://codesandbox.io/s/j755x416j9

I dont generally handle sessions directly. I let passportJS deal with that.
However, in the session constructor saveUninitialized is generally set to false when dealing with login events or trying to deal with race conditions in parallel requests.
From express-session npm
saveUninitialized
Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with race conditions where a client makes multiple parallel requests without a session.
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case.

Related

Unable to use the data sent to the server

This is my express server
const express = require("express");
const app = express();
const mongoose = require("mongoose");
require("dotenv").config();
const cors = require("cors");
const userData = require("./db");
var PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.urlencoded({ extended: false }));
mongoose
.connect("mongodb://localhost", {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log("Connected to database!!");
})
.catch((e) => {
console.log("Error : " + err);
});
app.get("/", (req, res) => {
res.json({ server: "Running" });
});
app.get("/login", (req, res) => {
res.json({ user: "true" });
});
app.post("/signup", (req, res) => {
console.log(req);
res.redirect("/");
});
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
and this is my React component
import React, { useState } from "react";
import "./Signup.css";
import axios from "axios";
import { useSelector } from "react-redux";
import { selectAuth } from "../../features/authSlice";
export default function Login() {
const isAuthenticated = useSelector(selectAuth);
const [user, setUser] = useState("");
const [pass, setPass] = useState("");
const handleSignup = async (e) => {
e.preventDefault();
var bodyFormData = new FormData();
bodyFormData.append("username", user);
bodyFormData.append("password", pass);
const res = await axios({
method: "post",
url: "http://localhost:3001/signup",
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" },
});
};
return (
<div className="signup__container">
<h2>Signup</h2>
<form className="signup__form" autoComplete="off">
<div className="signup__imgContainer">
<img
src={require("../../assets/avatar-placeholder.jpg").default}
alt="Avatar"
className="signup__avatar"
/>
</div>
<div className="signup__inputContainer">
<label for="uname">
<b>Username</b>
</label>
<input
type="text"
placeholder="Enter Username"
name="uname"
onChange={(e) => setUser(e.target.value)}
required
/>
<label for="psw">
<b>Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="psw"
required
onChange={(e) => setPass(e.target.value)}
/>
<button type="submit" onClick={handleSignup}>
Signup
</button>
<label>
<input type="checkbox" name="remember" /> Remember me
</label>
</div>
</form>
<div>{isAuthenticated.toString()}</div>
</div>
);
}
I am trying to post data using axios but I am unable to access this data in my backend. Am i doing it right, if yes then can anyone tell me what's wrong. and if no then how can I correct it to use the data.
I tried various things like sending the data as params but nothing worked on server it was always undefined however the console.log(req) gives something but I didn't see any of my post data in it.
add app.use(express.json());
if it does not work. then add body-parser in your package.
const express = require("express");
const bodyParser = require("body-parser"); // install body-parser
const cors = require("cors");
const app = express();
app.use(bodyParser.json({ limit: "50mb" }));
app.use(
bodyParser.urlencoded({
limit: "50mb",
extended: true,
parameterLimit: 50000,
})
);
app.use(express.json()); /// add
In the React app, you're using Content-Type multipart/form-data. When you use this Content-Type, the server needs to parse the request differently. This Content-Type is used when you want to upload a file in the request. It isn't the case here, so you should use Content-Type application/json instead.
Your request should be:
const res = await axios({
method: "post",
url: "http://localhost:3001/signup",
data: { username : user, password : pass},
headers: { "Content-Type": "application/json },
});
And in the Express application, you need to add a middleware to parse incoming requests in application/json Content-Type.
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use(express.json()); // <---- add this
In the route, you can see the data inside req.body
app.post("/signup", (req, res) => {
console.log(req.body);
res.redirect("/");
});

CORS issue with nodejs and react

Good day to all of you. I'm trying to build a log in and right now im struggling with the register form, I'm using react js for FrontEnd and nodejs/express for BackEnd.
I created the register form, I'm putting data from this register form inside an object, parsing it to a JSON obj and sending it to the node server through fetch api, however the cors thing is not letting this happen, i'm not sure why. The next is the code from the register(front side)
import React, { useState } from 'react';
import './Register.css';
import Title from './Title/Title';
import Label from './Label/Label';
import Input from './Input/Input';
function Register(){
const [ name, setName ] = useState('');
const [ lastname, setLastname ] = useState('');
const [ email, setEmail ] = useState('');
const [ username, setUsername ] = useState('');
const [ password, setPassword ] = useState('');
function handleChange(name, value){
if(name==='name')setName(value);
else if (name==='lastname')setLastname(value);
else if (name==='email')setEmail(value);
else if (name==='username')setUsername(value);
else if (name==='password')setPassword(value);
}
function handleSubmit(e){
e.preventDefault();
let account = { name, lastname, email, username, password };
if(account)console.log(account);
var url = 'http://localhost:3030/';
fetch(url, {
method: 'OPTION',
body: JSON.stringify(account),
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
///////////////////////////////////////////////////////////////////////////////////
}
return(
<div className='register-div'>
<Title text='Register Form'/>
<div className='squareout'>
<div className='square'>
<Label text='Name'/>
<Input attribute={{type:'text', name:'name'}} handleChange={handleChange}/>
</div>
<div className='square'>
<Label text='Last Name'/>
<Input attribute={{type:'text', name:'lastname'}} handleChange={handleChange}/>
</div>
<div className='square'>
<Label text='E-Mail'/>
<Input attribute={{type:'text', name:'email'}} handleChange={handleChange}/>
</div>
<div className='square'>
<Label text='Username'/>
<Input attribute={{type:'text', name:'username'}} handleChange={handleChange}/>
</div>
<div className='square'>
<Label text='Password'/>
<Input attribute={{type:'password', name:'password'}} handleChange={handleChange}/>
</div>
</div>
<button className='boton' onClick = {handleSubmit}>Register</button>
</div>
)
};
export default Register;
and this is from the server side:
const express = require('express');
const app = express();
const port = 3030;
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
app.use(express.static('public'));
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,DELETE");
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Access-Control-Allow-Headers, Content-Type, Authorization, Origin, Accept");
res.setHeader('Access-Control-Allow-Credentials', true)
next();
});
app.use(express.json());
app.post('http://localhost:3030/', (request, response) => {
console.log(request.body);
const data = request.body;
response.json({
name: data.name,
lastname: data.lastname,
email: data.email,
username: data.username,
password: data.password
})
});
and yet I'm getting this error:
Line 33: fetch(url, {
this is from the first code, the front side
Instead of reinventing the wheel, you can use CORS
And simply do:
const cors = require('cors')
const app = express()
app.use(cors())
Simply when facing an CORS issue remember these concepts,
It is not front-end apps fault (mostly)
you are trying to cross domain requests
those are blocked by default
You can allow this by allowOrigins with backend (syntax varies on language)
problem here is accessing localhost:3030 from localhost:3000
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors())
//for single origin
var corsOptions = {
origin: 'http://localhost:8080',
optionsSuccessStatus: 200 // For legacy browser support
}
app.use(cors(corsOptions));
source
If you set Access-Control-Allow-Credentials to true means you are allowing credentialed request
res.setHeader('Access-Control-Allow-Credentials', true)
Then you can't set Access-Control-Allow-Origin to *(wildcard)
res.setHeader("Access-Control-Allow-Origin", "*");
so solution here is that,
you have to set specific origin here,(frontend app origin for reactjs by default its http://localhost:3000/)
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000/");
In the end I found the solution, first instead of the method 'OPTION' I used 'POST' and the on the server side, i changed 'http://localhost:3030/' to just '/' and worked.

setting cookie with jwt token in react client using express backend

I am trying to set a cookie in the browser for authentication. When using POSTMAN the cookie is returned with no problem, as well as any other response I send. However in the react app, it is failing to fetch. It seems to be complaining about CORS, in particular this line of code being set to : res.header("Access-Control-Allow-Origin", "");
I have an app.js file in which I configure CORS and all of my routes, and my basic fetches work perfectly. When attempting to set a cookie in a route file, it fails to fetch. Here is the app.js file
//packages
var bodyParser = require ('body-parser')
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var mysql = require('mysql');
//routes
const accountRouter = require('./routes/account');
//express app
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(bodyParser.json());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//use routes
app.use('/account', accountRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// Tells Express to allows data to be sent across different origins
// required by CORS policy
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "localhost:3001");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// 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 route file that checks for an existing email, then verifies the password. After verifying the password I generate the token, and send it as a cookie. Again, in POSTMAN this functions fine.
var express = require('express');
var router = express.Router();
var bcryptjs = require('bcryptjs')
var cookieParser = require('cookie-parser');
var jwt = require('jsonwebtoken');
var pool = require('../database/accountsdb');
const saltRounds = 12;
function authenticate(req,res) {
//Check for existing email
//Create DB Connection
pool.getConnection(function(err, connection){
if(err) {
connection.release();
res.json({"code": 100, "status": "Error in database connection"});
return;
}
//Variables and SQL
let emailSQL ='SELECT intAccountID FROM accountdetails where strEmail = ?';
let email = req.body.email;
connection.query(emailSQL, email, function(err, result){
if(!err){
//check if matching row was found
if(result.length>0){
//Get password
let accountID = result[0].intAccountID;
let accountSQL = "SELECT strPassword, intAccountID FROM accounts WHERE intAccountID = ?";
connection.query(accountSQL, accountID, function(err, result){
if(!err){
//get password
let hashed = result[0].strPassword;
//get ID
let ID = result[0].intAccountID;
//compare passwords
bcryptjs.compare(req.body.password, hashed, function(err, result){
if(!err){
if(result== true){
let payload = {
check: true,
ID: ID
};
//generate token
let token = jwt.sign(payload, process.env.TOKEN_SECRET, {
expiresIn: 1440 //24 hours
});
//TESTING EXPIRE
//TESTING EXPIRE
let expiration= 1000;
//return token cookie
//NEED TO SEND COOKIE !!!!!!!!!!!!!!!!!!!!!
res.cookie('token', token, {
expires: new Date(Date.now() + expiration),
httpOnly: true,
});
}else{
//return failed
res.json({
message: 'Invalid Email or Password'
});
}
}else{
res.json({err: err});
}
})
}else{
//return error
res.json({err:err});
}
})
}else{
//return failed
res.json({
message: 'Invalid Email or Password'
});
}
}else{
connection.release();
res.json({err});
return;
}
connection.release();
})
connection.on('error', function(err){
res.json({"code": 100, "status": "Error in database connection"});
})
})
};
router.post('/authenticate', function(req, res){
authenticate(req, res);
});
module.exports = router;
Here is the react component to validate that a valid email was entered, the password is not empty, and the the API call to POST the data to express for authentication.
// Dependencies
import React, {Component} from 'react';
import validator from 'validator';
class Login extends Component{
constructor(props){
super(props);
this.state = {
email: '',
password:''
}
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeEmail = (event) => {
this.setState({email: event.target.value});
}
handleChangePass = (event) => {
this.setState({password: event.target.value});
}
verifyInput(data){
//Validate Email
if(validator.isEmail(data.email) == false){
return false;
}
}
handleSubmit(event){
let data = {
email: this.state.email,
password: this.state.password
}
let isValid= this.verifyInput(data)
if(isValid == false){
alert("Please enter a valid email address")
event.preventDefault();
}else{
//api parameters to register user
const url ='http://localhost:3001/account/authenticate'
const options = {
method:'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
body: JSON.stringify(data)
}
//call api
fetch(url, options)
.then(response=> {
console.log(response.headers)
}).catch(error=>console.log(error))
}
}
render (){
return(
<div className="register">
<form onSubmit={this.handleSubmit}>
<table>
<tbody>
<tr>
<td>Email:</td>
<td>
<input type="email" value={this.state.email} onChange={this.handleChangeEmail} />
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="text" value={this.state.password} onChange={this.handleChangePass}></input>
</td>
</tr>
<tr>
<td>
<input disabled={false} type="submit" value="Submit" onSubmit={(e) => this.handleSubmit(e)}/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
)
}
}
export default Login;
What do I do in order to fix this issue? The react client is on localhost:3000 and express on localhost:3001
Try installing http-proxy-middleware using npm or Yarn, then create src/setupProxy.js and place the following contents in it:
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
proxy({
target: 'http://localhost:3001',
changeOrigin: true,
})
);
};

request session not persistent - express-session

I'm trying to have a session containing user data in the node.js/express FW.
I'm using express-session. I'm not using session store yet.
I have 2 pages in the client (angular) where I iterate between - Login and Dashboard. The idea is to create the session after successful login, then routing to the dashboard page. In the dashboard page I have an anchor with routinlink to the login:
<a [routerLink]="['/login']" >BackToLogin</a>
When navigating back to the loginPage (when activating a route), I execute a service with an end-point to the express server which check if the request has a session with a request in it (I expect it to be). The problem is that I see that the session is not the same session (the id changes)
See my code:
Node.js side - server.js file:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require ('express-session');
var cookieParser = require('cookie-parser');
const SESS_NAME = 'sid';
app.use(session({
name:SESS_NAME,
key: 'user_sid',
resave:false,
saveUninitialized:false,
secure: process.env.NODE_ENV ==="production",
secret:'<some random text>',
cookie:{
httpOnly: true,
secure: process.env.NODE_ENV ==="production",
expires: 60000
}
}));
app.use(bodyParser.text());
app.use(bodyParser);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cors()); //No limitation for test reasons
app.use(cookieParser());
//disabled on purpose
//var sessionManagement = require('./middleware/sessionManagement');
// API
app.use("/", require("./api/v1/routes.js"))//This file includes:
/*
const express = require('express');
const router = express.Router();
router.use("/login", require('./login'));
router.use("/session", require('./session'));
module.exports = router;
*/
...etc
app.listen(config.port, () => console.log(`Process ${process.pid}: Listening on port ${config.port}`));
login.js on the server: responsible for validating user and store user data in session:
const express = require('express');
const router = express.Router();
const schema = require('./objectSchemaJson.schema.json');
const scehmaCheck = require('../../middleware/checkForSchema')(schema);//this is
a schema check (middleware) - if suceeded continue (next)
const storeSession = (req, dataResult) =>
{
if (<dataResult return with valid use data>) //This is "where the magic happanes"
{
req.session.user = {
username: <get userName from dataResult>,
ID: <Get ID from dataResult>,
Role: <Get Role from dataResult>
}
}
}
router.use("/", scehmaCheck, (req, res, next) => {
return GetUserDataFROmDB(req.body).then((dataResult) => { //reaching the DB - not mentioned here on purpose
storeSession(req, dataResult); // This is where the session set with user data
res.status(200).json(dataResult);
}).catch((err) => {
next({
details: err
})
});
});
module.exports = router;
This is the end point on the server that responsible for getting the session - session.js - This is where the problem appears - the res.session has a session ID which is different that the one I created after the login
const express = require('express');
const router = express.Router();
hasSession : function(req, res) //This is where the problem appears - the res.session has a session ID which is different that the one I created after the login
{
if (req.session.user)
{
res.status(200).json(
{
recordsets: [{Roles: req.session.Roles, UserName: req.session.user.username}]
});
}
else{
res.status(200).json({});
}
}
router.use("/", (req, res, next) => { return sessionManagement.hasSession(req, res, next)});
module.exports = router;
Client side:
//HTML:
<div>
<label>Username:</label>
<input type="text" name="username" [(ngModel)]="userName" />
</div>
<div>
<label>Password:</label>
<input type="password" name="password" [(ngModel)]="password"/>
</div>
<div>
<button (click)="login()">Login</button>
</div>
//COMPONENT:
login()
{
this.srv.login(this.userName, this.password).subscribe(result =>
{
if (<result is valid>)
{
this.router.navigate(['/dashboard']);
}
}
);
}
//This reach the node.js endpoint and routing to the session.js end point - it is executes when the router-outlet activated in the app.component:
/*
onActivate(componentRef : any)
{
if (componentRef instanceof LoginComponent)
{
componentRef.getSession();
}
}
*/
getSession() : void
{
this.sessionService.getSession().subscribe( result =>
{
if (<result is valid>)
{
this.router.navigate(['/dashboard']);
}
});
}
I found a similar question on github - no solution yet:
https://github.com/expressjs/session/issues/515
but it might be a cookie <-> server configuration issue.
Found the problem - the root cause was that the client didn't send a cookie when making an httprequest.
2 things needed to be done in order to solve the problem:
1. CORS Definition
Set the CORS definition to creadentials: true along with the origin (the host name of the client, which is probably with a different port\hostname):
app.use(cors({
origin: config.origin,
credentials: true
}));
2. Set crendentials
For every http rest method (get and post, in my case) add withCredentials property with a value of true:
return this.http.get<any>(<path>, { withCredentials: true })
or
return this.http.post<any>(<path>, <body>, { withCredentials:true })

NodeJS. Cannot get Credentials after auth login on client-side of React

I trying to understand what is the wrong with my credetrials inside my server code, because when I make Login from the client side, the credetrials does not recorgonizes inside the router.get('/auth/login') method, but when I do the same login action by the Postman with POST method and then reload the page with GET method the credetrials recorgonizes normally and I got the message, that I already loggined.
So, I actually want to say, that I do not have any problem with loginnig from the client side by "POST" method for router.post('/auth/login'), as for logs - user info transmits normally and credentials also creates, but on router.get('/auth/login') it does not callbacks in the res.json({session: req.session.userId, session2: req.session, log: 'You already logined!'});, where I gets just empty string...
My server code:
'use strict'
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
const bcrypt = require('bcrypt-nodejs');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const app = express();
const router = express.Router();
const EmployersSchemaDB = require('./SchemaDB/EmployersSchemaDB');
const User = require('./SchemaDB/ShemaAuthtificaion');
mongoose.connect('mongodb://myDB');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
res.setHeader('Cache-Control', 'no-cache');
next();
});
app.use(session({
secret: 'work hard',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
router.get('/', (req, res) => {
res.json('Hello on Homepage!');
});
router
.get('/auth/login', (req, res) => {
User.find((err, users) => {
if (err) { res.send(err) }
if (req.session.userId !== undefined) { // there is where I always falls...
res.json({session: req.session.userId, session2: req.session, log: 'You already logined!'});
} else {
console.log('User credentials!:', req.session.userId);
res.json({session: req.session.userId, session2: req.session});
console.log('---===--- \n Employers showed!: \n', users + '\n ---===---');
}
});
})
.post('/auth/login', (req, res, next) => {
if (req.body.password !== req.body.passwordConf) {
var err = new Error('Passwords do not match.');
err.status = 400;
res.send("passwords dont match");
return next(err);
}
if (req.body.email &&
req.body.username &&
req.body.password &&
req.body.passwordConf) {
let user = new User();
user.email = req.body.email;
user.username = req.body.username;
user.password = req.body.password;
user.passwordConf = req.body.passwordConf;
user.save((err) => {
if (err) { res.send(err) }
res.json({ message: 'Comment successfully added!', user });
console.log('---===--- \n Employer added: \n', user + '\n ---===---');
});
} else if (req.body.logemail && req.body.logpassword) {
User.authenticate(req.body.logemail, req.body.logpassword, function (error, user) {
if (error || !user) {
var err = new Error('Wrong email or password.');
err.status = 401;
return next(err);
} else { // this is the where credentials are creates. All work good!
req.session.userId = user._id;
console.log('Signed Cookies: ', req.session.userId, req.signedCookies)
console.log('User logined and redirected!');
return res.redirect('/employers');
}
});
} else {
var err = new Error('All fields required.');
err.status = 400;
return next(err);
}
});
app.use('/', router);
const port = process.env.API_PORT || 3016;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
My client code (just for info) : UPDATED FOR KEVIN
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import axios from 'axios';
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
navigate: false
}
}
handleSubmit = (e) => {
e.preventDefault();
let userLogin = {
logemail: e.target.email.value,
logpassword: e.target.password.value
}
axios.post('http://localhost:3016/auth/login', userLogin)
.then(function(){
axios.get('http://localhost:3016/auth/login', {withCredentials: true})
.then(res => console.log(res.data))
.catch(err => console.log(err));
this.setState({
navigate: true
})
})
.catch(err => {
console.error(err);
});
};
render() {
// if (this.state.navigate) {
// return <Redirect to="/employers" />
// }
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="exampleInputEmail1">Email address</label>
<input name="email" type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" />
<small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div className="form-group">
<label htmlFor="exampleInputPassword1">Password</label>
<input name="password" type="password" className="form-control" id="exampleInputPassword1" placeholder="Password" />
</div>
<div className="form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1" />
<label className="form-check-label" htmlFor="exampleCheck1">Check me out</label>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
}
export default LoginPage;
This may be a cross domain problem as you can login successfully with Postman.
AJAX calls will not send cookies in CORS environment by default. You need to set the withCredentials field of XMLHttpRequest object as true to send cookies even cross domain. Here is the official document.
As you are using axios, hope this setting would be helpful.
axios.defaults.withCredentials = true;
Update:
Please update your client code and make sure GET /auth/login are requested after POST /auth/login are completed, otherwise the Get request might be sent while POST request has not complete authenticate and set session. I recommend you change your code like following (put Get request after POST request are resolved):
axios.post('http://localhost:3016/auth/login', userLogin)
.then(function(){
axios.get('http://localhost:3016/auth/login').then(res => console.log(res.data).catch(e => console.log(e));
this.setState({
navigate: true
})
})
.catch(err => {
console.error(err);
});
```

Resources