4

I spent a long time trying figure it out why it's not working.

I'm implementing a login page using react. This page send the user and pass to backend (nodejs + express) using axios:

const login = useCallback(e => {
    e.preventDefault()
    fetch(process.env.REACT_APP_HOST + '/login', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: e.target.elements.username.value,
        password: e.target.elements.password.value
      })
    })
      .then(response => {
        if (response.ok) {
          return response.json()
        } else if (response.status === 401) {
          throw new Error('Invalid user or pass.')
        } else {
          throw new Error('An error ocurred')
        }
       ...
      })

  }, [])

In backend, I have a route that receive those data and check on ldap system. So I generate a token using JWT and save it on token

const express = require('express'),
    passport = require('passport'),
    bodyParser = require('body-parser'),
    jwt = require('jsonwebtoken'),
    cors = require('cors')
    cookieParser = require('cookie-parser')
    LdapStrategy = require('passport-ldapauth');

let app = express();
app.use(cookieParser())
app.use(cors());

....

app.post('/login', function (req, res, next) {

        passport.authenticate('ldapauth', { session: false }, function (err, user, info) {

            const token = jwt.sign(user, env.authSecret)
            res.cookie('cookie_token', token) //it doesn't set the cookie

            if (err) {
                return next(err)
            }
            if (!user) {
                res.sendStatus(401)
            } else {
                return res.status(200).send({ firstName: user.givenName});
            }
        })(req, res, next);
    });

The problem is that the token is empty, it's not being set.

mr.abdo
  • 445
  • 1
  • 5
  • 15

1 Answers1

3

Couple of things. In your react fetch post method you need to add

withCredentials: true,

beside the httpheader.

 fetch(process.env.REACT_APP_HOST + '/login', {
  method: 'POST',
  withCredentials: true,
  credentials: 'include',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    username: e.target.elements.username.value,
    password: e.target.elements.password.value
  })
})

After that in your nodejs part you are using cors but validating all origin. Thats not going to work with credentials. You need to use cors like this to validate specific origin and also turn credentials to true-

app.use(cors({credentials: true, origin: 'http://localhost:4200'}));

after that you can send your cookie by

res.cookie('cookie_token', token, { maxAge: 900000 }) 

chrom application cookie view

This way the cookie will arrive and once the cookie is arrived in client side you can retrieve the cookie with document.cookie or with any other package like "js-cookie"

Asif Rahman
  • 453
  • 7
  • 16
  • Exactly which part didn't work? because i tested this code in angular and nodejs with chrome and it works. Can you see the cookie in chrome dev console? – Asif Rahman Jun 17 '19 at 11:28
  • 2
    I solved it, I did what you suggested and I changed just this code: `credentials: 'include',` – mr.abdo Jun 17 '19 at 11:42