Search code examples
node.jsmongodbexpresscookiesexpress-session

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;

Solution

  • 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);
            });
    

    ```