chrispytoes
chrispytoes

Reputation: 1907

Nodejs won't set cookie for React CRA application even with proxy

I have a nodejs/express + React CRA application, and I'm trying to set a cookie from nodejs. The server is on port 4001, so in my React application's project.json I have "proxy": "http://localhost:4001" set, but the cookie still won't get set in the browser.

I've tested it in production mode as well, with the React application being served from nodejs directly and it all works fine there.

Here is how I am setting the cookie. I've tried several different combinations of options here and they all have the same result.

res.cookie('jwt', token, {
    httpOnly: false,
    sameSite: false,
    signed: false,
    secure: false,
    encode: String
});
res.header('Access-Control-Allow-Credentials', 'true');

Edit: On the client side I am using Axios for my ajax requests.

Edit:

Here is the endpoint function for login (POST /api/users/login):

login: function(req, res) {
    User.findOne({
        $or: [{email: req.body.username}, {username: req.body.username}]
    }).exec().then(user => {
        if(user) {
            if(user.checkPassword(req.body.password)) {
                jwt.sign({ userID: user._id }, 'secret', (err, token) => {
                    res.cookie('jwt', token, {
                        httpOnly: false,
                        sameSite: false,
                        signed: false,
                        secure: false,
                        encode: String
                    });
                    res.header('Access-Control-Allow-Credentials', 'true');
                    res.status(200).send({ status: 'ok', message: 'Success'});
                });
            }
            else {
                return res.status(401).send({ status: 'error', message: 'Invalid username/password combination. Please try again.' });
            }
        }
        else {
            return res.status(401).send({ status: 'error', message: 'Invalid username/password combination. Please try again.' });
        }
    }, err => {
        return res.status(500).send({ status: 'error', message: 'unexpected error' });
    });
}

Here is the client-side login code:

login(username, password) {
    return new Promise((resolve, reject) => {
        axios({
            method: 'post',
            url: 'http://localhost:4001/api/users/login',
            data: {
                username,
                password
            }
        }).then((res) => {
            resolve(res.data);
        }, (err) => {
            reject(err);
        });
    });
}

Server is on port 4001, React CRA server is on 3000

Upvotes: 16

Views: 6701

Answers (2)

Mattia Fantoni
Mattia Fantoni

Reputation: 955

According to what riwu mentioned cookie domain should match, in my case setting "cookieDomainRewrite": "localhost", works

Below complete config for setupProxy.js in React:

const {createProxyMiddleware} = require('http-proxy-middleware');

module.exports = function (app) {
    app.use(
        '/api',
        createProxyMiddleware({
            target: 'http://localhost:8000',
            changeOrigin: true,
            cookieDomainRewrite: "localhost",
        })
    );
};

Upvotes: 0

Roy Wang
Roy Wang

Reputation: 11270

To allow the browser to set cookies and adhere to Same Origin Policy, your client code should query http://localhost:3000/api/users/login (same host as client) instead of the (proxied) server url (port 4001).

You can also specify the base url as ${window.location.origin}/api or just /api.

Upvotes: 10

Related Questions