1

Backend

I am trying make a JWT cookie based authentication work. I am currently performing the following cookie setting as part of a login route in the backend API.

res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});

Later when I am auth(ing) any other requests, I am reading off of this cookie and testing it in a passport-jwt strategy.

I have gotten this work in postman - when I perform a login and access a secured route - it works perfectly fine + the cookie is also getting set in postman.

Frontend

Now, I am performing the following call stack in the frontend just to test the working,

axios.post("http://localhost:3001/login", logInParams, config)
    .then(result => {
        // User is logged in so push them to the  respective dashboard
        console.log(result);
        axios.get("http://localhost:3001/user/profile")
            .then(result => {
                console.log(result);
            })
            .catch(err => {
                console.log(err);
                return;
            })
    })
    .catch(err => {
        console.log(err)
        return;
    });

So basically, I log the user in and that works perfectly fine - I am getting a JSON response as intended, but the call is supposed to set a cookie which it is not and hence the next axios.get call is not returning successfully. Though for some reason I see session cookie and a CSRF cookie. Only this authCookie or the jwt-cookie is not getting set.

Some extra details

I am using cors with default parameters - could this be an error of this? Or is there any changes I have to do with axios? I have seen some answers and being new to MERN I don't really understand them. Does someone know about this or have experienced it and solved it?

Rohan Asokan
  • 634
  • 4
  • 22

3 Answers3

1

Are you running the server from a different port than the one that provides the client (i.e: webpack-dev-server running on localhost:3000 and Express server on localhost:3001)? This looks like a same-site cookie issue. In the latest versions of some browsers such as Chrome cookie setting is being blocked when this one comes from a different origin site. This is due to security concerns; you can learn more about same-site cookies here.

The change made in the browsers is related to the default value they give to a cookie policy property called same-site. The old workaround was treating all the cookies from a different origin as None by default, but last year it changed to consider the same-site policy as Lax when no same-site policy was not explicitly provided by the server. This is a desirable behaviour from the browser because it helps at preventing third party sites making use of the cookie provided by the server, but you can edit it by different ways:

  • Changing the default same-site policy of your browser settings (the article about same site cookies explains).
  • Sending a same-site:'None' from the server. Express has a way to do so explaind on its docs. Keep in mind browsers also have a new policy to ignore same-site:'None' when the cookie is not marked as Secure, what demands the use of HTTPS (I guess this behaviour can be edited in your browser settings if you want to check while using HTTP).

Obviously, any strategy that demands the users to change their browser settings is a no-go, so running HTTPS with Secure cookies is mandatory for same-site:'None'.

You always have the approach of making both browser and client same origin, so you won't have any issues at all with same-site (i.e. the Express server returning the index.html of the production build of your client as its main static). I haven't found any way to configure CORS module to have a default same site cookies policy (or its sole use as middleware to change it), likely not its purpose, but you can try by adding a dynamic origin config.

As far as I've seen, Postman does not support the same-site cookie property yet, so that would explain why is it working on Postman but not on the browser.

1

From the looks of it - it seems to be an issue with how cors works and I am adding the following answer to help anyone else coming across it. Thank me later :)

Server Side

You will have a cors in your server that looks like this,

app.use(cors());

You will have to set credentials to true and set the allowedHeaders and origin as follows,

app.use(cors({
    credentials: true,
    allowedHeaders: ['Content-Type', 'Authorization'],
    origin: ['http://localhost:3000']
}));

This is because normally cookies are not allowed to be set in the browser if the server and the client are in the same port. To handle this the above is required on the server side.

Client Side

We also have to pass the cookies when we are sending the request and to do this with axios just add the following in the index.js of your react app as so,

axios.defaults.withCredentials = true;
Rohan Asokan
  • 634
  • 4
  • 22
-1

I think you should write send('cookies are set') at the end in res.cookie('authCookie', token, {maxAge: 900000, httpOnly: true});

AkhanIskak
  • 52
  • 3