node.jsexpresscorsaxiossession-cookies

What to include in headers when making preflight complex CORS request?


An app I'm making has the front-end and node-back end hosted separately (cross origin). The front-end is making a call to the back end for login where the x-session-token is sent back. Because this is a custom header I understand this to be a complex request and therefore a pre-flight check is needed.

In the server.js file I have the following snippet (which I understand to enable CORS pre-flight checks):

const express = require('express');
const cors = require("cors");
const app = express();

const corsOptions = {
  origin: true,
  credentials: true
}

app.options('*', cors(corsOptions));

The front-end makes the following axios call:

axios.post('/api/user/login', logInObj,
    {withCredentials:true},
    {crossDomain:true},
    {'Access-Control-Request-Headers': 'Content-Type'},
    {'Access-Control-Request-Method': 'post'}
    )
    .then(logInResponse => ...

Which is responded to by this in the back-end:

router.post('/api/user/login', (request, response) => {
...
response.setHeader('Access-Control-Allow-Credentials', true);
response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
response.setHeader('Access-Control-Allow-Method', 'get', 'post', 'options');
response.setHeader('Access-Control-Allow-Origin', request.get('Origin'));
response.setHeader('Access-Control-Max-Age','86400')
response.setHeader('Access-Control-Expose-Headers', 'Access-Control-Allow-Origin');
...

When I console log the response header on the back-end it contains:

An x-session-token matches that in MySQL

Access-Control-Allow-Origin is listed as http://localhost:3000 not wildcard (*)

However the console.log of the response in the browser has null for the session-token which tells me the browser is blocking the CORS return data (X-Session-Token in this case). What am I missing in the request or response header?


Solution

  • I think you miss the exposed Header you want to send back. "x-session-token" ? Also try to use app.use instead of just app.options and let the cors package handle it unless it is just specific to this route of course

    app.use(cors({
      credentials: true, 
      exposedHeaders: ['Set-Cookie', 'Content-Length', 'Accept', 'X-Requested-With', 'X-HTTP-Method-Override', 'x-session-token' ],
      methods: ['GET', 'POST', 'OPTIONS', 'HEAD'],
      optionsSuccessStatus: 204,
      origin: 'http://localhost:3000'
    })