28

I'm trying to implement client login using fetch on react.

I'm using passport for authentication. The reason I'm using fetch and not regular form.submit(), is because I want to be able to recieve error messages from my express server, like: "username or password is wrong".

I know that passport can send back messages using flash messages, but flash requires sessions and I would like to avoid them.

This is my code:

fetch('/login/local', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ username: this.state.username, password: this.state.password, }), }).then(res => { console.log(res.headers.get('set-cookie')); // undefined console.log(document.cookie); // nope return res.json(); }).then(json => { if (json.success) { this.setState({ error: '' }); this.context.router.push(json.redirect); } else { this.setState({ error: json.error }); } }); 

The server sends the cookies just fine, as you can see on chrome's dev tools: Network - Cookies Network - Headers

But chrome doesn't set the cookies, in Application -> Cookies -> localhost:8080: "The site has no cookies".

Any idea how to make it work?

3
  • can you post the code of your server side? Commented Aug 29, 2016 at 10:42
  • Maybe this can be helpful for you stackoverflow.com/questions/36035445/… Commented Aug 29, 2016 at 10:48
  • Found out the problem, see my answer. Thanks, btw. Commented Aug 30, 2016 at 6:23

4 Answers 4

18

The problem turned out to be with the fetch option credentials: same-origin/include not being set. As the fetch documentation mentions this option to be required for sending cookies on the request, it failed to mention this when reading a cookie.

So I just changed my code to be like this:

fetch('/login/local', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, credentials: 'same-origin', body: JSON.stringify({ username: this.state.username, password: this.state.password, }), }).then(res => { return res.json(); }).then(json => { if (json.success) { this.setState({ error: '' }); this.context.router.push(json.redirect); } else { this.setState({ error: json.error }); } }); 
Sign up to request clarification or add additional context in comments.

8 Comments

This didn't work for me , even after setting the credentials: 'same-origin',/'include.
This does not work even with the credentials as same-origin
credentials: 'same-origin' is the default value, no? developer.mozilla.org/en-US/docs/Web/API/Request/credentials
I fixed this by setting credentials: 'include' and also setting the header "Access-Control-Allow-Origin" to "localhost:3000" (my Webstorm is serving the react pages from a different server than my express server) and also setting the header "Access-Control-Allow-Credentials" to "true"
This answer doesn't actually show how to get a cookie value from the response, which was the original question.
|
8

From Differences from jQuery section of the Fetch API on Mozilla:

  • fetch() won't receive cross-site cookies. You can’t establish a cross site session using fetch(). Set-Cookie headers from other sites are silently ignored.
  • fetch() won’t send cookies, unless you set the credentials init option. Since Aug 25, 2017: The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.)

1 Comment

Can one use xhr instead and that will work?
3

I had to include credentials: 'include' in the fetch options:

fetch('...', { ... credentials: 'include', // Need to add this header. }); 

Comments

0

I spent a long time but nothing worked for me.

after trying several solutions online this one worked for me.

Hopefully it will work for you too.

{ method: "POST", headers: { "content-type": "API-Key", }, credentials: "include", } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.