Gershon Papi
Gershon Papi

Reputation: 5106

fetch: Getting cookies from fetch response

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?

Upvotes: 28

Views: 90450

Answers (4)

Yangshun Tay
Yangshun Tay

Reputation: 53169

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

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

Upvotes: 3

Konstantin Komelin
Konstantin Komelin

Reputation: 755

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.)

Upvotes: 8

Mohsin Latif
Mohsin Latif

Reputation: 505

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",
}

Upvotes: 0

Gershon Papi
Gershon Papi

Reputation: 5106

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 });
      }
    });

Upvotes: 17

Related Questions