Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express Session Cookie Not Being Set when using React Axios POST Request

The Setup

I have setup a frontend environment using create-react-app. In this environment I use Axios to make a POST request to my Node JS Express Backend Server /login endpoint. I setup sessions middleware using express-sessions and storing the sessions in Redis. I have all this running in localhost currently.

Environment

  • React App - http://localhost:3005/kp (Note: the service runs on http://localhost:3005 however, all the routes have /kp in them)

  • Express Backend - http://localhost:5001

  • Redis - http://localhost:6379

What Works

When the frontend sends the request to the backend the Express server does it's thing and authenticates the user; it stores the username in the req.session.username (this is just as a test), Redis console shows that the key value store was successful, the frontend network tab shows a 200 status with a Set-Cookie response header and a tab that shows the cookie (screenshots below).

The Problem

Everything seems to be working fine but the cookie is not set in the Browser. I have refreshed the page, tried again many times and yet it will not set the cookie in any browser (Google Chrome & Safari). I am getting frustrated because it seems as though Chrome acknowledges that the Set-Cookie is present but ignores it for some reason.

What I've Tried

Axios

  1. I have tried setting withCredentials: true - Does not work
  2. Verified the cookie with Set-Cookie is being sent back to the frontend after the POST request

Backend

  1. I have checked my CORS policies to but they seem fine; however, I am not great with CORS so there could be misconfiguration there
  2. Tried setting credentials to true in CORS policy
  3. Verified the session with variables are being set with Redis.

Code

React Frontend Axios POST Request

      axios.post('http://localhost:5001/login', loginBody, {
        headers: {
          'Content-Type': 'application/json'
        }
      },
        { withCredentials: true }
      )
        .then((res) => {
          console.log(res);
        })
        .catch((error) => {
          console.log(error);
          this.setState({
            errorMessage: `Server Error`,
            loading: false
          });
        });

Express Server

const express = require('express');
const http = require('http');
const cors = require('cors');
const socketServer = require('./src/sockets');
const bodyParser = require('body-parser');
const session = require('express-session');
const redis = require('redis');
const redisClient = redis.createClient();
const redisStore = require('connect-redis')(session);
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const port = process.env.PORT || 5001;
const { loginRoutes } = require('./src/routers');
const app = express();

redisClient.on('error', (err) => {
  console.log('Redis error: ', err);
});

app.use(cors({
  origin: '*',
  methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
  credentials: true
}));

// Redis session storage setup
// API Docs for express-session: https://www.npmjs.com/package/express-session
const sessionMiddleware = session({
  secret: process.env.REDIS_SECRET || 'testing12345',
  name: 'session',
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: false
  },
  store: new redisStore(
    {
      host: process.env.REDIS_HOSTNAME,
      port: process.env.REDIS_PORT,
      client: redisClient,
      ttl: 604800
    }
  )
});

// Uses session middleware
app.use(sessionMiddleware);

app.use(bodyParser.json({ limit: '5mb' }));

const server = http.createServer(app);

// Starts Socket Server
socketServer(server, sessionMiddleware);

// Uses the routes from the router directory
app.use(loginRoutes);

server.listen(port, () => {
  console.log(`Listening on port: ${port}`);
});

Screenshots

Network Response

Response and Request Headers Axios

Request Cookie

Response Cookie

Application Cookies

Application Cookies

As you can see the cookie is missing in the list of browser cookies. I have a feeling it is something small but I have not been able to find anything.

I am not getting any errors in any service. Thank you in advance for your help.

like image 831
Austin Mutschler Avatar asked Aug 04 '20 17:08

Austin Mutschler


2 Answers

Solution

As Michał Lach pointed out I put withCredentials in the wrong place in the Axios call.

Frontend Axios

  axios.post('http://localhost:5001/login', loginBody, {
    headers: {
      'Content-Type': 'application/json'
    },
    withCredentials: true
  })

However, once I did this I began to get CORS error. The CORS error was you cannot have a wildcard '*' in your Access-Control-Allow-Origin (origin) configuration. For this example I changed it to point only to http://localhost:3005; however, there are ways to do dynamic whitelists as documented here: https://www.npmjs.com/package/cors#configuring-cors-w-dynamic-origin

Backend

app.use(cors({
  origin: 'http://localhost:3005',
  methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
  credentials: true
}));

Once I made these changes the cookie started being set on the frontend correctly.

like image 93
Austin Mutschler Avatar answered Oct 13 '22 00:10

Austin Mutschler


Are you sure, you are setting axios options correctly ?

You have :

    axios.post('http://localhost:5001/login', loginBody, {
    headers: {
      'Content-Type': 'application/json'
    }
  },
    { withCredentials: true }
  )
    .then((res) => {
      console.log(res);
    })
    .catch((error) => {
      console.log(error);
      this.setState({
        errorMessage: `Server Error`,
        loading: false
      });
    });

Try this:

    axios.post('http://localhost:5001/login', loginBody, {
    headers: {
      'Content-Type': 'application/json'
    },
    { withCredentials: true }
  }
        ....
like image 43
Michał Lach Avatar answered Oct 13 '22 00:10

Michał Lach