305

I am sending requests from the client to my Express.js server using Axios.

I set a cookie on the client and I want to read that cookie from all Axios requests without adding them manually to request by hand.

This is my clientside request example:

axios.get(`some api url`).then(response => ...

I tried to access headers or cookies by using these properties in my Express.js server:

req.headers
req.cookies

Neither of them contained any cookies. I am using cookie parser middleware:

app.use(cookieParser())

How do I make Axios send cookies in requests automatically?

Edit:

I set cookie on the client like this:

import cookieClient from 'react-cookie'

...
let cookie = cookieClient.load('cookie-name')
if(cookie === undefined){
      axios.get('path/to/my/cookie/api').then(response => {
        if(response.status == 200){
          cookieClient.save('cookie-name', response.data, {path:'/'})
        }
      })
    }
...

While it's also using Axios, it is not relevant to the question. I simply want to embed cookies into all my requests once a cookie is set.

Kunok
  • 8,089
  • 8
  • 48
  • 89
  • 1
    how did you set the cookie on the client? show code example please :) – Tzook Bar Noy Apr 05 '17 at 06:00
  • @TzookBarNoy Added code in question – Kunok Apr 05 '17 at 10:07
  • 2
    Cookies are set by servers with Set-Cookie not by the client, i guess you mean reading the cookie on the client. According to the Cookie protocol, the client should include a Cookie header in its requests to the the cookie issuer server. – Hans Poo Nov 02 '18 at 15:46
  • Look this https://stackoverflow.com/questions/53898031/how-to-set-cookies-express-react-js/55804086#55804086 – Ender Bonnet Apr 23 '19 at 04:15

19 Answers19

558

You can use withCredentials property.

XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request.

axios.get(BASE_URL + '/todos', { withCredentials: true });

Also its possible to force credentials to every Axios requests

axios.defaults.withCredentials = true

Or using credentials for some of the Axios requests as the following code

const instance = axios.create({
   withCredentials: true,
   baseURL: BASE_URL
})
instance.get('/todos')
fingerpich
  • 8,500
  • 2
  • 22
  • 32
  • 71
    note that this will only work when the `Access-Control-Allow-Origin` in response header isn't set to wildcard (*) – Jerry Zhang Sep 12 '17 at 18:52
  • 1
    @JerryZhang What do you mean? I am facing the same issue, if `Access-Control-Allow-Origin` isn't set to `*` it means, I won't make request to that server because of CORS right – samayo Sep 13 '17 at 12:26
  • 20
    The response needs set `Access-Control-Allow-Origin`'s value to the domain you want to make XHR request from. e.g. `https://a.com` is the server, `https://b.com` is the client, and `https://b.com` is loaded in someone's browser and is using `XMLHTTPRequest` to make request to `https://a.com`. In addition for `XMLHTTPRequest` (initiated in `https://a.com`) to set `withCredential: true`, the server - `https://b.com` also needs to be configured so the response header contains `Access-Control-Allow-Origin: https://a.com` – Jerry Zhang Sep 14 '17 at 17:19
  • I have a little problem with this... if I have a as server b as client (ie. react page), than if I set this to true, it will send the a credentials, not the b credentials... LOL... OK, it's not funny. – golddragon007 Oct 25 '17 at 11:23
  • 4
    @JerryZhang Did you get the ordering wrong? `https://b.com` in your example represents the client, so therefore `XMLHTTPRequest` should be initiated in `b` instead of `a` ? – atjua Nov 27 '18 at 05:52
  • may I ask you to have a look at an `axios` related question here : https://stackoverflow.com/questions/59470085/vue-js-validation-fails-for-file-upload-in-axios-when-multipart-form-data-used ? – Istiaque Ahmed Dec 24 '19 at 14:29
  • 1
    I addition, make sure the POST request that sets the cookie also includes "withCredentials: true" as well, not only just your subsequent GET requests – rantao Jun 24 '20 at 21:53
  • what about JSESSIONID cookie? – Ion Utale Aug 14 '20 at 09:20
  • 1
    Might be related to @rantao his comment. But make sure you also add `withCredentials: true` to the call **receiving** the cookie. Otherwise the next calls you do won't use the retrieved cookie – hwcverwe Apr 19 '21 at 11:06
  • @JerryZhang could you checkout my question here: https://stackoverflow.com/questions/71436719/authorization-in-react-with-django-rest-api-backend – the__hat_guy Mar 11 '22 at 17:44
  • Note that with `axios.post`, `withCredentials:true` should be in the *third* argument and not be part of the data (see https://stackoverflow.com/a/59995231/194707) – kevlar Feb 08 '23 at 00:08
71

TL;DR:

{ withCredentials: true } or axios.defaults.withCredentials = true


From the axios documentation

withCredentials: false, // default

withCredentials indicates whether or not cross-site Access-Control requests should be made using credentials

If you pass { withCredentials: true } with your request it should work.

A better way would be setting withCredentials as true in axios.defaults

axios.defaults.withCredentials = true

Fatih Acet
  • 28,690
  • 9
  • 51
  • 58
  • 21
    Sending credentials with _every_ request is a bad practice. These controls are in place for a reason. Talking to another service, sending all your cookies - whether they're used are not, is ripe for exploitation. – colm.anseo Mar 12 '19 at 14:21
  • 17
    @colminator only cookies that have the server domain as their domain will be sent. (By default they will not be sent to any subdomains either and there can be further filtering based on path.) In effect we are only sending the server cookies which were set by the server. – M3RS Apr 04 '20 at 06:56
  • Do you know if on the client side, I can change (e.g. remove) the cookies set by the server? – Zennichimaro Oct 26 '20 at 08:50
  • 1
    @colm.anseo I believe this setting is off by default because browser in general blocks everything CORS by default. Majority of ppl won't need it, hence the default settings are like that - to serve the majority. Those who need different behaviour have to explicitly ask for it by playing with the settings. Strict by default, loosen it up if you know what you are doing. – avepr May 26 '21 at 01:39
30

It's also important to set the necessary headers in the express response. These are those which worked for me:

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', yourExactHostname);
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});
Eyk Rehbein
  • 3,683
  • 3
  • 18
  • 39
  • Adding **`X-PINGOTHER`** into `Access-Control-Allow-Headers` has been mandatory for me (Node.js 6.9 with Express 4.16, Chrome 63). Check **JakeElder**'s post on this GitHub issue: https://github.com/axios/axios/issues/191#issuecomment-311069164 – Maxime Pacary Jan 15 '18 at 09:05
  • this was necessary along with `axios.defaults.withCredentials = true;` on my frontend axios config. Once removing the create-react-app proxy in package.json, we needed to enable withCredentials, as well as include the above middleware in our express app. Thank you – jboxxx Apr 10 '21 at 21:03
  • Does this work if the request came from a localhost:3000? – Koala Sep 08 '22 at 08:12
20

So I had this exact same issue and lost about 6 hours of my life searching, I had the

withCredentials: true

But the browser still didn't save the cookie until for some weird reason I had the idea to shuffle the configuration setting:

Axios.post(GlobalVariables.API_URL + 'api/login', {
    email,
    password,
    honeyPot
}, {
    withCredentials: true,
    headers: {
        'Access-Control-Allow-Origin': '*', 
        'Content-Type': 'application/json'
    }
});

Seems like you should always send the 'withCredentials' Key first.

Mr.Singh
  • 1,421
  • 6
  • 21
  • 46
  • 3
    Wooooooooowww mate! I've been hounded by this forever, my new favorite answer on the internet. Thank you very much! For anyone who may be wondering why their GET request says true for isAuthenticated, but their POST request does not, your POST must be formatted as such: axios.post(`URL`, {data}, {withCredentials: true}). while your GET allows for the withCredentials to be sent with the data: axios.get(`URL`, {data, withCredentials: true}). At least for me in my react -> express operations. – DORRITO Jun 27 '21 at 00:10
  • This is a necessary part of the answer – Maxim Zhukov Jul 14 '22 at 05:46
  • I lost 3 days and now still success, adding any option – May'Habit Aug 09 '22 at 04:49
  • @DORRITO your answer made my day.Thanks a ton.Ordering is most important thing.withCredentials: true should always come after data in case of POST request.In GET request it is not mandatory. – Pramod Kishore Jan 01 '23 at 08:46
  • I don't think `withCredentials` needs to be first in the third argument, but it just needs to be part of the third argument and not in the second argument which is the data. – kevlar Feb 08 '23 at 00:09
  • @kevlar I've been coding javascript for 10+ years, never in my working life I encountered this haha, but for some reason having the withCredentials below headers didn't work and moving it up worked... Now, it wouldn't be the first time I didn't save a change and suddenly saving it made it work, it makes no sense that changing the order affects... But is a good answer, the post and get are different – Luigi Cordoba Granera Feb 09 '23 at 14:34
18

I am not familiar with Axios, but as far as I know in javascript and ajax there is an option

withCredentials: true

This will automatically send the cookie to the client-side. As an example, this scenario is also generated with passportjs, which sets a cookie on the server

punkbit
  • 7,347
  • 10
  • 55
  • 89
RITESH ARORA
  • 487
  • 3
  • 11
  • 1
    I set but nothing change, I see response cookie in request but why I cannot see it in storage? is this reason why I cannot send it? – May'Habit Aug 09 '22 at 04:08
  • above flag is used to add cookies(cookies for you domain only) automatically in request. It have nothing to do with storage(i think you are referring local storage). You need to read it from local stoage and send it alongside manually. – RITESH ARORA Aug 10 '22 at 08:47
  • I know but i added it and nothing happen, cookie can not send to server – May'Habit Aug 10 '22 at 09:11
14

You can use withCredentials property to pass cookies in the request.

axios.get(`api_url`, { withCredentials: true })

By setting { withCredentials: true } you may encounter cross origin issue. To solve that you need to use

expressApp.use(cors({ credentials: true, origin: "http://localhost:8080" }));

Here you can read about withCredentials

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
13

Fatih's answer is still valid and great in 2022.

Also axios.defaults.withCredentials = true will do the trick.

It seems passing { withCredentials: true } to individual axios calls is deprecated.

Leon
  • 255
  • 3
  • 12
11

What worked for me:

Client Side:

import axios from 'axios';

const url = 'http://127.0.0.1:5000/api/v1';

export default {
  login(credentials) {
    return axios
      .post(`${url}/users/login/`, credentials, {
        withCredentials: true,
        credentials: 'include',
      })
      .then((response) => response.data);
  },
};

Note: Credentials will be the body of the post request, in this case the user login information (Normally obtained from the login form):

{
    "email": "user@email.com",
    "password": "userpassword"
}

Server Side:

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

const app = express();
const port = process.env.PORT || 5000;

app.use(
  cors({
    origin: [`http://localhost:${port}`, `https://localhost:${port}`],
    credentials: 'true',
  })
);
Manuel Reyes
  • 260
  • 2
  • 10
  • 1
    What goes in the `credentials` argument of `login` function? – geoidesic Apr 11 '21 at 14:21
  • In your `axios.post`, does `withCredentials: true` negate the need for `credentials: 'include'`? I don't see the latter option in the axios docs: https://axios-http.com/docs/req_config. – kevlar Feb 08 '23 at 00:16
8

How do I make Axios send cookies in requests automatically?

set axios.defaults.withCredentials = true;

or for some specific request you can use axios.get(url,{withCredentials:true})

this will give CORS error if your 'Access-Control-Allow-Origin' is set to wildcard(*). Therefore make sure to specify the url of origin of your request

for ex: if your front-end which makes the request runs on localhost:3000 , then set the response header as

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');

also set

res.setHeader('Access-Control-Allow-Credentials',true);
prak
  • 133
  • 1
  • 9
7

for people still not able to solve it, this answer helped me. stackoverflow answer: 34558264

TLDR; one needs to set {withCredentials: true} in both GET request as well the POST request (getting the cookie) for both axios as well as fetch.

probhonjon
  • 302
  • 5
  • 8
  • 2
    This is crucial. I had overlooked this in my code and spent a good deal of time wondering why `{ withCredentials: true }` in GET request did not have any effect. – yogmk Dec 03 '19 at 10:14
  • 1
    EXTREMELY important! There is a lot of discussion about adding `withCredentials: true` to the request config but not this detail. I spent almost 2 days trying to solve the problem until I came across this – rantao Jun 24 '20 at 21:52
6

Another solution is to use this library:

https://github.com/3846masa/axios-cookiejar-support

which integrates "Tough Cookie" support in to Axios. Note that this approach still requires the withCredentials flag.

machineghost
  • 33,529
  • 30
  • 159
  • 234
3

After trying for 2 days long and after trying out from the suggestions here this is what worked for me.

  1. express:

    • cors: cors({ origin: "http:127.0.0.1:3000", credentials: true, })
    • Cookie : Make sure your cookie has secure: true, sameSite: "None"
  2. Frontend(React)

  • axios.defaults.withCredentials = true; (withCredentials : true did not work for me) to the places where you request the cookie as well as to the place where you send the cookie (GET/POST)

Hope this helps others as well.

malfoy
  • 58
  • 1
  • 6
1

You are getting the two thinks mixed.

You have "react-cookie" and "axios"

react-cookie => is for handling the cookie on the client side

axios => is for sending ajax requests to the server

With that info, if you want the cookies from the client side to be communicated in the backend side as well, you will need to connect them together.

Note from "react-cookie" Readme:

Isomorphic cookies!

To be able to access user cookies while doing server-rendering, you can use plugToRequest or setRawCookie.

link to readme

If this is what you need, great.

If not, please comment so I could elaborate more.

Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341
Tzook Bar Noy
  • 11,337
  • 14
  • 51
  • 82
  • What does `plugToRequest` exactly do? I thought to access cookies on the node server, all one needs is the `cookie-parser` middleware (assuming Express)? – geoboy Sep 27 '17 at 22:38
  • cookie httpOnly can not read by js, how to set it to request header? – May'Habit Aug 09 '22 at 10:25
1

For anyone where none of these solutions are working, make sure that your request origin equals your request target, see this github issue.

I short, if you visit your website on 127.0.0.1:8000, then make sure that the requests you send are targeting your server on 127.0.0.1:8001 and not localhost:8001, although it might be the same target theoretically.

Sebastian
  • 1,593
  • 4
  • 26
  • 41
1

This worked for me:

  • First, I had to make a new instance of axios with a custom config
  • Then, I used that axios instance to make a post request

See code below:

const ax = axios.create({
  baseURL: 'yourbaseUrl',
  withCredentials: true,
});

const loginUser = () => { 
  ax.post('/login', {
    username: state.values.email, 
    password: state.values.password
  }).then(function(response) {
    return response
  }).then().catch(error => console.log(error));
}

source: https://www.npmjs.com/package/axios#creating-an-instance

Mr.Singh
  • 1,421
  • 6
  • 21
  • 46
YankeeCruz
  • 11
  • 1
0

This won't apply to everyone, but I was using a React frontend with Vite and it was serving the localhost as 127.0.0.1:5173, which is what I put as the CORS allowable domain. As soon as I both to localhost everything worked as expected!

vancy-pants
  • 1,070
  • 12
  • 13
0

// use this while creating axios instance

const API = axios.create({
    baseURL: "http://localhost:4000", // API URL
    withCredentials: true,
});

// USE THIS MIDDLEWARE in app.js of backend first, install cors npm i cors

var cors = require("cors"); // This should be at the end of all middlewares

const corsOptions = {
    origin: "http://localhost:3000",
    credentials: true, //access-control-allow-credentials:true
    optionSuccessStatus: 200,
};

app.use(cors(corsOptions));
Saurav Gami
  • 61
  • 1
  • 3
0

In my case, the problem was with the cookie, not with Axios; although I was receiving and sending the cookie from / to the same domain / subdomain / host, I was expecting it to work with different resources in different paths - but my coookie was acting like I had set it to a single Path, even though I omitted that attribute. Explicitly setting Path=/; in the cookie solved the issue.

David V McKay
  • 122
  • 2
  • 12
-1

Using express session setting sameSite to 'lax' worked for me:

app.use(session({
  secret: '$ome$essi@nsecre+',
  saveUninitialized: true,
  resave: false,
  store: new MemoryStore({
    captureRejections: true,
  }),
  cookie: {
    secure: false,
    sameSite: 'lax'
  }, // max age set to 24 hours
}));
Sudhir
  • 766
  • 8
  • 17