axios cannot send cookie with request even with withCredential: true

30,656

Solution 1

If you plan on using this mulitple times, then just create an axios config:

client/src/utils/axiosConfig.js

import axios from 'axios';

const baseURL = process.env.NODE_ENV === "development"
  ? "http://localhost:3001/"
  : "http://example.com"

const app = axios.create({
    baseURL,
    withCredentials: true
})

/* 
  The below is required if you want your API to return 
  server message errors. Otherwise, you'll just get 
  generic status errors.

  If you use the interceptor below, then make sure you 
  return an "err" (or whatever you decide to name it) message 
  from your express route: 
  
  res.status(404).json({ err: "You are not authorized to do that." })

*/
app.interceptors.response.use(
  response => (response), 
  error => (Promise.reject(error.response.data.err))
)

export default app;

client/src/actions/exampleAction.js

import app from '../utils/axiosConfig';

export const exampleAction = () => (
  app.get('orders') // this will be defined as baseURL + "orders" (http://localhost:3001/orders)
    .then(res => console.log(res))
    .catch(err => console.log(err))
)

Then for your API, instead of specifying CORS headers, you can simply use cors wherever you're defining your express middleware:

const cors = require('cors');
const origin = process.env.NODE_ENV === "development" 
  ? "http://localhost:3000" 
  : "http://example.com"

app.use(
  cors({
    credentials: true,
    origin
  }),
);

Solution 2

Now 2020, Chrome add more annoying restricts to cross domain cookies settings, you must set cookies with SameSite to none, otherwise Chrome will refuse to send cookies. More, if you set SameSite, you must set secure.

Below is an example for how to set this change in nginx, it may not work with your situation, but for reference.

proxy_cookie_path / "/; secure; SameSite=none";

Solution 3

I figure out my mistake. Change axios code to

axios.defaults.withCredentials = true;
axios('http://localhost:3001/orders', {
  method: 'GET',
  withCredentials: true
}).then(res => {
     console.log(res);
   }).catch(err => {
     console.log(err.response);
   })

I still want to ask why does this change help so any answer will be appreciated

Solution 4

axios.post('http://localhost:5000/api/auth/login',{ userEmail, userPassword },{
        withCredentials: true,
      })


const cors = require("cors");
expressApplication.use(cors({
 origin: ["http://localhost:2000", "http://localhost:3000"],
 credentials: true
}));

Share:
30,656
Huy Nguyen
Author by

Huy Nguyen

Just a noob programmer

Updated on July 27, 2021

Comments

  • Huy Nguyen
    Huy Nguyen almost 3 years

    I already setup on server like this

        app.use((req, res, next) => {
      res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
      res.header(
        'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization,  X-PINGOTHER'
      );
      res.header('Access-Control-Allow-Credentials', true);
      res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
      next();
    });
    

    and the axios on client side (react) like this

    axios.defaults.withCredentials = true;
    axios('http://127.0.0.1:3001/orders', {
      method: 'GET',
      withCredentials: true
    }).then(res => {
         console.log(res);
       }).catch(err => {
         console.log(err.response);
       })
    

    Everything works fine when I test with Postman and type directly to chrome. Any idea what's wrong with my code?

  • Norfeldt
    Norfeldt about 2 years
    Would you mind adding some description of what it does? Some of the code is for the front end and the rest for the back end, right?