Search code examples
node.jsexpresscookiespassport.jsexpress-jwt

Cookie is not set using express and passport


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.


Solution

  • 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"