Request API with cookie fails in different javascript functions - javascript

I am not able to receive the resources from an API using different functions in javascript.
It works as follows:
In one tab of the browser I open the application webclient and receive a cookie for that domain:
first_browser_tab
In another tab I open a page of a different domain and using javascript I request the ressource from the API. It runs over a gateway which has the same domain as my endpoint:
second_browser_tab
The cookie is not sent in the request and for this reason I get an authentication error from the endpoint to my request.
I tried to send the request in different ways and it allways fails due to the endpoint authentication.
See the code:
Using fetch
const urlToApiFetch = 'https://app.apple.com/api';
fetch(urlToApiFetch, {
method: "GET",
mode: "cors",
credentials: "include",
headers: {
"Authorization": "Bearer 12345",
"x-api-key": "12345",
}
})
.then((response) => {
console.log(response);
})
.catch ((error) => {
console.log(error)
});
Using XMLHttpRequest
const urlToApiXMLHttpRequest = 'https://app.apple.com/api';
let testUrl = urlToApiXMLHttpRequest;
let xhr = new XMLHttpRequest();
xhr.open("get", testUrl, true);
xhr.setRequestHeader("Authorization", "Bearer 12345");
xhr.setRequestHeader("x-api-key", "12345");
xhr.withCredentials = true;
xhr.onreadystatechange = function(r) {
console.log(r);
}
xhr.send();
Using jQuery
const URL = "https://app.apple.com/api";
$.ajax({
url: URL,
crossDomain: true,
method: "GET",
xhrFields: {
withCredentials: true
},
headers: {
"Authorization": "Bearer 12345",
"x-api-key": "12345",
}
}).done(function(data, status){
console.log(data);
console.log(status);
}).fail(function(data, status){
console.log(data);
console.log(status);
});
Does anyone have an idea on what is wrong? Why does the cookie is not sent?
Thanks a lot

I found the issue...
The response header was missing the parameter:
Access-Control-Allow-Credentials: true
More details here: https://javascript.info/fetch-crossorigin

Related

CORS on react axios, but not on vanilla

I am trying to get data from a AWS endpoint using React/axios, but when I try to make a request I get this CORS error:
Access to XMLHttpRequest at 'https://myAWS.com/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
when I try on my hosted github pages build, I also get the same error. But when I use Vanilla js on another hosted website it works, am I sendig my requests wrong on axios?
VANILLA
let body = {
"name": "Bbbb 202",
"email": "bbbb2220#bob.com",
"password": "122",
"wallet": "bbbbB202222"
};
var http = new XMLHttpRequest();
var url = 'https://myAWS.com/login';
http.open('POST', url, true);
//Send the proper header information along with the request
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.send(body);
REACT
async SendRequest(method, url, callback, body){
axios.request({
method: 'POST',
data: JSON.stringify(body),
headers: {
"Content-Type": "application/json;charset=utf-8",
"Authorization": "Bearer " + localStorage.getItem("token"),
},
url: url
})
.then(response => {
console.log(response);
callback({
status: response.status,
data: response.data,
});
})
.catch(err => {
console.log(err);
callback({
status: err.status,
data: err,
});
});
}
These are not the same request. The 'vanilla' request looks like it might qualify for what's known as a 'safe request'. To qualify as a safe request, content-type must be application/x-www-form-urlencoded (or 2 others), and not use any restricted HTTP methods.
I wrote more extensively about it here as well: https://evertpot.com/no-cors/

401 Unauthorized REST API in lightning web component salesforce

I'm trying to execute query using REST API, in a lightning web component.
the request in Postman returning result with success (enabling Follow Authorization header)
but in the JavaScript in lightning web component it returns 401 Unauthorized
the code in the java script is a follow :
let sessionId = 'tokken';
let baseUrl = window.location.origin;
let header = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer " + sessionId,
};
if (sessionId) {
let options = {
method: "GET",
mode: 'no-cors',
redirect: 'follow',
headers: header,
};
fetch(baseUrl + '/services/data/v50.0/query/?q=SELECT+name+from+Account', options).then((response) => {
console.log(JSON.stringify(response));
if (!response.ok) {
// throw Error(JSON.stringify(response));
} else {
return response.json();
}
}).then((repos) => {
console.log(repos, repos);
});
}
am I missing something ?
Since you can not pass the value Authorization to no-cors mode, you will need to add CORS configuration in your SalesForce as safe endpoint where they let you make a call.
You can not send Authorization header with "no-cors" mode.
mode: "no-cors"only allows a limited set of headers in the request:
Accept
Accept-Language
Content-Language
Content-Type with a value of application/x-www-form-urlencoded, multipart/form-data, or text/plain

XMLHttpRequest successful while fetch is blocked

I am trying to access an API from the front-end and i tried both xhr and fetch api requests.
When using fetch, i received the error "Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:5500' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
However, when using XHR, I do not receive a headers not present warning and it sucessfully fetches the JSON from the api.
I don't quite understand CORS, but my understanding is that there was no header present on the api I was requesting and therefore could not fetch the API. BUT, how was xhr able to fetch the api with the assumed lack of headers on the API? How was the request possible in an XMLHTTPRequest but not a fetch request? How would I use fetch to fetch this API? I have included both my fetch and XHR code below for reference.
Fetch Code:
fetch(requestURL, {
headers: {
"Content-Type": "application/json",
'Authorisation': 'Basic' + apiKeySecured,
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": false,
"api-key": apiKeySecured,
}
}).then(function (response) {
return response.json();
})
.then(function (myJson) {
console.log(JSON.stringify(myJson));
})
.catch(error => console.error(error));
XHR code:
var xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("GET", requestURL);
xhr.setRequestHeader(`api-key`, apiKeySecured);
xhr.send();
You need to set the mode option for fetch.
From the docs:
// Example POST method implementation:
postData(`http://example.com/answer`, {answer: 42})
.then(data => console.log(JSON.stringify(data))) // JSON-string from `response.json()` call
.catch(error => console.error(error));
function postData(url = ``, data = {}) {
// Default options are marked with *
return fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, cors, *same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, same-origin, *omit
headers: {
"Content-Type": "application/json; charset=utf-8",
// "Content-Type": "application/x-www-form-urlencoded",
},
redirect: "follow", // manual, *follow, error
referrer: "no-referrer", // no-referrer, *client
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(response => response.json()); // parses response to JSON
}
What is triggering the pre-flight in your original code?
Every single one of those extra headers you added
"Content-Type": "application/json",
'Authorisation': 'Basic' + apiKeySecured,
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": false,
Not one of these was added to XHR, so don't add it to fetch
Your fetch should be
fetch(requestURL, {
headers: {
// remove all those random headers you added
"api-key": apiKeySecured
},
mode: 'cors' // add this
}).then(response => response.json())
.then(function (myJson) {
console.log(JSON.stringify(myJson));
})
.catch(error => console.error(error));
Now it is equivalent to your XHR code

Basic authentication (or any authentication) with fetch

Couldn't find any documentation on this, so before I dig deep in code does anyone out there know how to use basic authentication when making a REST request using 'fetch' (https://github.com/github/fetch).
Just tried the following line, but the header was not set in the request:
fetch('http://localhost:8080/timeEntry', {
mode: 'no-cors',
headers: { 'Authorization': 'Basic YW5kcmVhczpzZWxlbndhbGw=' }
})
.then(checkStatus)
.then(parseJSON)
.then(function(activities) {
console.log('request succeeded with JSON response', data);
dispatch(activitiesFetched(activities, null));
}).catch(function(error) {
console.log('request failed', error);
dispatch(activitiesFetched(null, error));
});
The username and password is my own first and last name, using curl it works.
If I put { 'Accept' : 'application/test' } Accept is set, just not Authorization... strange.
Just for me to able to continue I added credentials: 'include' which makes the browser to prompt for username and password which is used for communicationg with the REST backend. Just for testing, will use OAuth further on.
fetch('http://localhost:8080/timeEntry', {
mode: 'no-cors',
credentials: 'include'
})
.then(checkStatus)
.then(parseJSON)
.then(function(activities) {
console.log('request succeeded with JSON response', data);
dispatch(activitiesFetched(activities, null));
}).catch(function(error) {
console.log('request failed', error);
dispatch(activitiesFetched(null, error));
});
no-cors mode prevents the headers from being anything other than simple headers.
"Authorization" header doesn't fit to simple headers. See more here: https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
Note that if you use fetch with Authorization header you will NOT establish a session. You will have to manually add that header for every request. Navigating to secured path would also not be possible.
So to make this work You should pre-authenticate with XMLHttpRequest. You can do this like so:
var authUrl = location.origin + '/secured-path/';
var http = new XMLHttpRequest();
http.open("get", authUrl, false, login, pass);
http.send("");
if (http.status == 200) {
//location.href = authUrl;
} else {
alert("⚠️ Authentication failed.");
}
Note that above is synchronous so you don't need a callback here.
So after doing this you can use fetch without headers e.g. this request should be successful:
fetch(authUrl, {
method: 'get',
}).then(function(response) {
console.log(response);
});
Since it looks like the library you are using is a polyfill for Fetch API, I'm going to work off of the assumption that the syntax should carry through as well.
The samples I found on Mozilla's page indicate that the fetch method signature is fetch('API_ENDPOINT', OBJECT) where object looks like:
myHeaders = new Headers({
"Authorization": "Basic YW5kcmVhczpzZWxlbndhbGw="
});
var obj = {
method: 'GET',
headers: myHeaders
})
So the method becomes:
fetch('http://localhost:8080/timeEntry', obj)
.then(checkStatus)
.then(parseJSON)...
I have not tested this code, but it seems consistent with what I was able to find. Hope this points you in the right direction.

Sending plain ajax HTTP request with custom header

I have an existing java client on top of which IOS, andriod developers prepared a simple http request based applications. And am trying to achieve same in HTML5 app.
And the difficulty right now am facing is sending an custom header within the AJAX request like authorization with encrypted login details.
I tried to achieve same on various REST clients and able to send "AUTHORIZATION : BASIC XXXXXX=" in request header. And getting proper json response"
But if i try same using ajax call am not able to send similar request header. Request sending as OPTIONS instead of GET and the authorization tag is not going properly as a header instead it's going as "Access-Control-Request-Headers:authorization".
and here is the snippets i have tried.
<script>
//$.ajaxSetup({ headers: { 'Authorization': 'Basic XXXXXXX='} })
// get form data for POSTING
var vFD = new FormData(document.getElementById('upload_form'));
var oXHR = new XMLHttpRequest();
oXHR.open('POST', "https://123.123.123.123:229/");
//oXHR.send(vFD);
var body = 'Basic XXXXXXX=';
var mUrl = "https://123.123.123.123:229/?json";
var client = new XMLHttpRequest();
client.open('GET', mUrl, true);
client.withCredentials = true;
client.crossDomain = true,
client.setRequestHeader('Authorization', 'Basic XXXXXXX=');
client.send(body);
simpleHttpRequest();
function simpleHttpRequest() {
alert("calling ");
var headers = {
"Authorization": "Basic XXXXXXX="
};
$.ajaxSetup({ "headers": headers });
$.ajaxSetup({ 'cache': false });
$.ajax({
type: "GET",
withCredentials: true,
// data: {
// address: 'http://www.google.com'
// },
crossDomain: true,
Headers: { "Authorization": "Basic XXXXXXX=" },
dataType: "jsonp",
url: mUrl,
cache: false
});
}
xhrToSend();
function xhrToSend() {
// Attempt to creat the XHR2 object
var xhr;
try {
xhr = new XMLHttpRequest();
} catch (e) {
try {
xhr = new XDomainRequest();
} catch (e) {
try {
xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
statusField('\nYour browser is not' +
' compatible with XHR2');
}
}
}
}
xhr.withCredentials = true;
xhr.open('GET', mUrl, true);
xhr.setRequestHeader("Authorization", "numberOfBLObsSent");
xhr.send();
};
</script>
And all the different ways getting failed. Please help me.
Thanks in advance.
The issue is related to the cross-domain nature of the request. When you make a cross-domain request which contains custom headers, the request is first "preflighted" to the server via the OPTIONS method, and the server must respond with a header Access-Control-Allow-Headers: your-custom-header. Once this is received, the ajax client will then (automatically) issue the actual request.
More on preflighted requests

Categories