Why do I get error code 401 when sending post request - javascript

From the following request I get status code 302 redirect. But I want to send cookies I've received from the response with the redirect to the next page. Right now I get status code 401 when sending the request, and I've figured out that it's because I need to send the cookies along with the redirect, but I don't get the cookies until I fetch the url that gives me the redirect. How do I do that?
async function login (url) {
let request = await fetch(url, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
body: 'username=name&password=pass&submit=login',
})
return request
}

In general body data type must match the Content-Type header. so in your case you have to use
body: new URLSearchParams({
'userName': 'name',
'password': 'pass',
'grant_type': 'password'
}),

Related

Trying to use fetch instead of axios to make a POST request, but the response from the fetch request returns an error, whereas axios doesn't

I have a function which uses Axios to send a POST request which goes through successfully and I get the right response. Now I want to try using fetch to do the exact same POST request. Unfortunately, the fetch request returns a 415 Unsupported Media Type response error and I have no idea why.
Currently:
onBeforeUnload = () => {
try {
const defaultPresence = {
presence: 'AVAILABLE',
message: '',
};
const url = getServerURL() + urls.PRESENCE;
axios.post(
url,
defaultPresence,
{
headers: {
Authorization: `Bearer ${getAccessToken()}`,
},
},
);
} catch (error) {
console.log(error);
}
}
The fetch code I've used to replace the Axios POST request.
fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${getAccessToken()}`,
},
body: defaultPresence,
});
fetch does not recognise plain objects as the body.
If you want to send JSON then you need to encode the data and set the content-type header yourself.
fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${getAccessToken()}`,
"Content-Type": "application/json",
},
body: JSON.stringify(defaultPresence),
});

Bad request response to fetch REST API

I have built an API and app that uses that API. When I POST method via Postman, it works fine, but when I try fetching it via app, I get a bad request 400 status response. What am I doing wrong?
Here is my JavaScript code:
const myForm = document.getElementById('loginForm');
myForm.addEventListener('submit', function(e) {
e.preventDefault();
const url = 'https://thawing-peak-69345.herokuapp.com/api/auth';
const myHeaders = new Headers();
myHeaders.append('Accept', 'application/json, text/html, */* ');
myHeaders.append('Content-Type', 'application/json, charset=utf-8')
const formData = {
email: this.email.value,
password: this.password.value
};
console.log(formData);
const fetchOptions = {
method: 'POST',
mode: 'no-cors',
cache: 'no-cache',
headers: myHeaders,
body: JSON.stringify(formData)
};
fetch(url, fetchOptions)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.log(err))
})
Request
Response
Headers request:
Headers response:
You said:
mode: 'no-cors',
This is a declaration that you are not doing anything that requires permission be granted with CORS. If you try to do anything that does need permission, it will be silently ignored.
myHeaders.append( 'Content-Type', 'application/json, charset=utf-8')
Setting the Content-Type header to a value not supported by the HTML form element's type attribute requires permission from CORS. application/json is not such a value.
Consequently, the request is sent as text/plain.
Since it isn't marked as being JSON, the server throws a 400 error.
You need to:
Remove mode: 'no-cors',
Make sure that the service you are making the request to will use CORS to grant you permission (or to use a service on the same origin as the request).

Vue.js Fetch throws 404 and api response

I can't make a POST request in Vue.js. It was giving me CORS issues, but I added
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
to the API and they went away. I can get valid responses from the API using Postman while using the same email and password (Postman ignores CORS).
Here is my Fetch request:
<script>
export default {
data () {
return {}
},
methods : {
login : function () {
console.log('Logging in');
// axios({
// method : 'post',
// url : 'https://www.example.com/login',
// headers : {'content' : 'application/json'},
// data : {
// email : 'emailHere',
// password : 'passwordHere'
// }
// })
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
fetch('https://www.example.com/login', {
method: 'POST',
body: JSON.stringify({
email : 'emailHere',
password : 'passwordHere'
})
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err))
}
}
}
</script>
https://www.example.com/api/v1/authenticate/login 404 (Not Found)
{status: false, message: "Invalid credentials"}
I tried Axios, and still gives me 404, but not the "Invalid Credentials" response.
In other applications I have used jquerys ajax successfully with the same API, so the API seems to allow javascript requests. But Fetch and Axios don't like it.
I have a Login.vue component that has a button
<a id="login-btn" #click.prevent="login">{{ $t('loginPage.loginButtonText') }}</a>
Any help would be appreciated! Thanks!
You are missing Content-Type header. Try setting headers in your request. Fetch demands that you set headers explicitly since it is a low-level API. Your server may reject as it doesn't recognize appropriate Content-Type. Try this:
fetch('https://www.example.com/login', {
method: 'POST',
// THIS IS IMPORTANT
headers: new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json',
}),
body: JSON.stringify({
email : 'emailHere',
password : 'passwordHere'
})
})
Also, remember two things with fetch:
First getting 404 using fetch doesn't mean that your request has failed. If a server responds 4xx or 5xx error, then fetch is considered successful. Only when a network error occurs, fetch is rejected. So if you get 404, it means the request has reached server but there is a problem with the client side.
Second, try setting mode to cors in you fetch request. Thought the default value of mode is cors.

Fetch, set-cookies and csrf

I m using Isomorphic fetch in my application and I m having some troubles dealing with CSRF.
Actually, I m having a backend that sends me a CSRF-TOKEN in set-cookies property :
I have read somewhere that it's not possible, or it's a bad practice to access this kind of cookies directly inside of my code.
This way, I tried to make something using the credentials property of fetch request :
const headers = new Headers({
'Content-Type': 'x-www-form-urlencoded'
});
return this.fetcher(url, {
method: 'POST',
headers,
credentials: 'include',
body: JSON.stringify({
email: 'mail#mail.fr',
password: 'password'
})
});
This way, I m able to send my CSRF cookie back to my server to serve my need (it's a different one, because it s not the same request) :
My problem
My problem is that my backend needs to receive a x-csrf-token header and so I can't set it to my POST request.
What I need
How can I do to put the value of set-cookies: CSRF-TOKEN into the next request x-csrf-token header ?
It looks like in your scenario you are supposed to read from CSRF-TOKEN cookie. Otherwise it would be marked HttpOnly as JSESSIONID. The later means you cannot access it from the web page but merely send back to server automatically.
In general there is nothing wrong in reading CSRF token from cookies. Please check this good discussion: Why is it common to put CSRF prevention tokens in cookies?
You can read your cookie (not HttpOnly, of cause) using the following code
function getCookie(name) {
if (!document.cookie) {
return null;
}
const xsrfCookies = document.cookie.split(';')
.map(c => c.trim())
.filter(c => c.startsWith(name + '='));
if (xsrfCookies.length === 0) {
return null;
}
return decodeURIComponent(xsrfCookies[0].split('=')[1]);
}
So fetch call could look like
const csrfToken = getCookie('CSRF-TOKEN');
const headers = new Headers({
'Content-Type': 'x-www-form-urlencoded',
'X-CSRF-TOKEN': csrfToken
});
return this.fetcher(url, {
method: 'POST',
headers,
credentials: 'include',
body: JSON.stringify({
email: 'test#example.com',
password: 'password'
})
});
Yes header name depends on your server. For example django usecase to setup CSRF token using fetch is like this:
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=UTF-8',
'X-CSRFToken': get_token
},

Unable to fetch POST without no-cors in header

On making request like that:
return fetch(
'http://localhost:8000/login',
{ method: 'POST',
headers: new Headers(
{"Content-Type": "application/json",
"Accept":"application/json"}
),
body: JSON.stringify(
{'name': 'Tom', 'password': 'Soyer'}
)
}
).then( response => { console.log(response);})
.catch(err => console.log(err))
request running with method OPTIONS instead POST.
Only on adding mode: 'no-cors' request become POST:
return fetch(
'http://localhost:8000/login',
{ method: 'POST',
mode: 'no-cors',
headers: new Headers(
{"Content-Type": "application/json",
"Accept":"application/json"}
),
body: JSON.stringify(
{'name': 'Tom', 'password': 'Soyer'}
)
}
).then( response => { console.log(response);})
.catch(err => console.log(err))
but response not ok than (even if network response status is 200): {type: "opaque", url: "", status: 0, ok: false, statusText: ""…}
I suppose it because
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded multipart/form-data text/plain
described here https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Is any way bring to live POST json data with fetch?
The custom Content-Type header you're sending causes your request to be preflighted, which means an OPTIONS request, containing some metadata about the POST request that is about to be dispatched, will be sent before the actual POST request.
Your server needs to be prepared to deal with this OPTIONS request. You haven't specified what the server is written in, but with express for example, you can register a middleware that intercepts all 'OPTIONS' requests, sets the Access-Control-Allow-Origin: * and Access-Control-Allow-Headers: Content-Type headers, and responds with 200.
If it is possible for you to make the request using a 'Content-Type': 'text/plain' header, that would solve your problem. Alternatively you could use something that bypasses XHR entirely, like JSONP.
When using non-cors, all headers must be valid simple-headers. The only valid values for the content-type header that qualifies as a simple-header is:
headers: [
['Content-Type', 'application/x-www-form-urlencoded'],
['Content-Type', 'multipart/form-data'],
['Content-Type', 'text/plain'],
]
Exceptions with contingencies:
headers: [
['Content-Type', 'application/csp-report'],
['Content-Type', 'application/expect-ct-report+json'],
['Content-Type', 'application/xss-auditor-report'],
['Content-Type', 'application/ocsp-request'],
]
simple-header
cors-protocol-exceptions
If you are trying to call an api and getting stuck with this in your react app you can add a proxy to the server and the cors error will get removed
just add this line at the package.json
"proxy":"url-to-your-server",

Categories

Resources