1

I have a MERN + Passport.js application that is using fetch to make a call to my express API in order to retrieve data stored in a cookie. I have my React frontend routed to localhost:3000, and my backend routed to localhost:3001. My cookies are not being saved, and thus my session is not persisting within my browser. It is not an issue with the express-sessions or passport middleware, as when I use POSTMAN to execute the necessary calls to my API, the cookie is stored and the session persists. It is only when I attempt to pass this information through/to my front end that things go wrong. I have been stumped for a while and can't seem to find an answer anywhere.

This is the line that I am using to save the cookie:

handleLogin(event) {
        event.preventDefault();
        fetch("http://localhost:3001/users/login", {
            // credentials: 'include',
            credentials: 'same-origin',
            method: "post",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },   
        body: JSON.stringify({
            username: this.state.username,
            password: this.state.password
            })
        })
        // .then( (response) => response.json())
        .then( (response )=> {
            if(response.message){
                alert(response.message);
            }
        })

Which correctly calls my API, which logs the current session, user data, and cookie.

Upon refreshing and making another request, I lose the cookie (it was never properly stored in the first place I think), and all session data.

This is the get request that I make whenever I navigate to a new page:

componentDidMount(){
        var current_user = "";
        fetch("http://localhost:3001/users/", {
            // credentials: 'include',
            credentials: 'same-origin',
            method: "get",
            headers: {
                'Accept':'application/json',
                'Content-Type': 'application/json'
            }        
        })
        // .then( (response)=> response.json())
        .then( (response)=> {
            if(response.user){
                current_user = response.user;
                this.setState({
                    user: current_user
                }), ()=> console.log(response);
            }
        })
    }

In response, I get an undefined user and no other response, and the cookie is never stored in my browser. But again, if I do this in POSTMAN, strictly doing the POST request followed by that GET request, the proper user data is returned and the cookie is shown in POSTMAN as well. Any idea as to why fetch is not passing the cookie information back to my front end? I have tried both credentials: 'include' and credentials: same-origin.

Thank you!

1 Answer 1

2

It seems like the problem, or at least part of it, is your use of same-origin. From Mozilla docs (italics my own):

omit: Never send cookies.

same-origin: Send user credentials (cookies, basic http auth, etc..) if the URL is on the same origin as the calling script. This is the default value.

include: Always send user credentials (cookies, basic http auth, etc..), even for cross-origin calls.

The definition of "same origin" does not include different ports.

If you change same-origin to include, fetch should start managing your cookies correctly.

If not - do you know for sure that the cookie is "never stored in the browser"? With Chrome, you can check chrome://settings/siteData.

Sign up to request clarification or add additional context in comments.

4 Comments

I have attempted to use include instead of same-origin, however when I switch the credentials to include I don't even get a console.log of the output (which is very odd). And yes, typically I check chrome's developer window and go to 'Application' and then head over to 'Storage' to check if my cookies are there -- and they are not there on my front-end (localhost:3000). I also don't get a cookie to localhost:3001 (my backend).
To clarify: you've tried changing same-origin to include in both requests? And the result is that the first one doesn't throw an alert, and the second one doesn't do a console.log? There's no errors?
Ah, I've been working through it and it seems that when I set credentials to include, I do get an error - Initially it was a CORS error stating that I couldn't use the wildcard (*) to allow my front end access to the backend's credentials. I've debugged that, and now I'm working through an error that states: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. I am currently trying to explicitly set the allow credentials header to true.
I wasn't - but I installed it and got it working. Thank you - the fix ended up being to set my credentials to 'include' in my fetch call, as it was treated as CORS request (the documentation on different ports of the same host being same origin or cross origin is pretty conflicting). After setting that I had to set some more CORS options using the Node.js CORS package: whitelisting my React frontend and enabling setting the "Credentials" header to true.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.