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:
But chrome doesn't set the cookies, in Application -> Cookies -> localhost:8080: "The site has no cookies".
Any idea how to make it work?
If you set credentials to same-origin : Fetch will send 1st party cookies to its own server. It will not send cookies to other domains or subdomains. If you set credentials to include : Fetch will continue to send 1st party cookies to its own server.
If you want to pass cookies with this request, you can do so by passing the credentials option to the fetch request. fetch("http://example.com/data.json", { credentials: "same-origin" }) . then(response => response. json()) .
Use the fetch() method to return a promise that resolves into a Response object. To get the actual data, you call one of the methods of the Response object e.g., text() or json() . These methods resolve into the actual data.
In class-based components, you can get the cookie by using a withCookies() higher-order component. import React, { Component } from "react"; import { withCookies } from "react-cookie"; class App extends Component { state = { // getting the cookie user: this. props. cookies.
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 });
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With