node.jsreactjscookiesaxioscross-domain

Cookie in Set-Cookie header not being set


I'm sending a request to a node.js server from a reactjs client using axios as shown below.

import axios from 'axios';

const apiClient = axios.create({
  withCredentials: true,
  baseURL: 'http://localhost:8080'
});

async function(payload) {
  try {
    debugger;
    let result = await apiClient.post('/auth/signup/', payload);
    debugger;
    return result;
  } catch (error) {
    debugger;
    throw error;
  }
}

The node.js endpoint sets a cookie in the response as shown below.

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

router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
router.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag']} ));
router.use(cookieParser());


router.post('/signup', async (req, res, next) => {
  debugger;
  let database = req.app.locals.database;
  try {
    let user = await database.findByUsername(req.body.username);
    let token = await jwt.sign({username: user.username}, config.secret, {expiresIn: "15m"});
    res.cookie('jwt',  token, {
      maxAge: 900,
    });
  } catch (error) {
    debugger;
    return res.status(503).send({ auth: false, message: 'Database error.' });
  }
});

The Set-Cookie header of the response contains the cookie as expected.

Set-Cookie Header

However, Chrome does not appear to be setting the cookie, as I cannot see the cookie in the Application window of the Developer Console.

Cookies

I've looked at the answers to the following questions, which mention setting { withCredentials: true } in the axios configuration and not using a wildcard origin for cors in node.js, but I am already doing both.

Set-Cookie header not setting cookie in Chrome

Set cookies for cross origin requests

Any ideas as to why the cookie is not being set and how to fix this issue?


Solution

  • Though you are hosting client and server in the same domain as http://localhost, your ports are different, so the same-origin policy is failed here. You can check https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy.

    As so, you making a CORS request, check your network tab in your developer tools in your current browser, you might see a preflight request OPTIONS, before your client sends POST request to your server.

    The server must specify headers to accept the origin of your next request - POST request from http://localhost:8000 with method POST, you can refer to https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

    HTTP/1.1 204 No Content
    Connection: keep-alive
    Access-Control-Allow-Origin: http://localhost:3000
    Access-Control-Allow-Methods: POST // Your next request will use POST method
    Access-Control-Max-Age: 86400
    Access-Control-Allow-Credentials: true // cookies accepted
    

    Added:

    In Set-Cookie, Max-Age must be non-zero digit. It be rounded up into integer according to RFC doc. For express.js, cookies `maxAge property is on the scale of miliseconds

    The solution will be set the maxAge property as second * 1000

        res.cookie('jwt',  token, {
          maxAge: 10000,
        });