Answer a question

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.

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.

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐