AJAX - Response to preflight request doesn't pass access control check - javascript

I am try to do a technical test for an interview and have hit a snag with fetching some data from an API. The error message im getting is this:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Here is my request:
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch('https://rss.itunes.apple.com/api/v1/us/apple-music/top-albums/all/100/non-explicit.json', {
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json"
}
})
.then(handleErrors)
.then((response) => response.json())
.catch((e) => {
throw Error(e);
});
After googling the issue the majority of answers seem to suggest you need to add: Access-control: Allow-Origin to the resource to enable CORS. I obviously don't have access to do that on iTunes API so I am wondering if there is another way around it.
The get request works fine in postman and returns me the data that I need so i'm wondering if it's one of my request headers thats not being set properly?
Apparently other people have managed to complete the test so i'm quite sure there is something wrong with my request.

Related

TypeError on fetch request on "e-raktakosha" web site api

I am new to javascript. I was trying to make an api call.
My code
const options = {
method: 'GET',
headers: {
Authorization: 'Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==',
'content-type': 'application/json',
}
};
fetch(
'https://www.eraktkosh.in/BLDAHIMS/bloodbank/nearbyBB.cnt?hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0',
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));
but I encountered with an error saying
Error: Failed to fetch
This api call works perfectly with Hoppscotch
If I try to hit the url right on my url bar, it also works fine.
Any help is strongly appreciated. Thank you from Manoranjan
As other People already mentioned, you can't pass a Body when doing a GET HTTP call, instead you can pass Query Params
Notice this part on the URL
hmode=GETNEARBYSTOCKDETAILS&stateCode=21&districtCode=378&bloodGroup=all&bloodComponent=11&lang=0
Still looking into the code it seems the server have a cors policy, look at this sandbox
See this codesandbox -> https://codesandbox.io/s/peaceful-mcclintock-exuzol?file=/src/index.js
Summary:
GET accept body/payload but it could cause errors, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
Using the Web API (new headers, new request) for doing the HTTP call
It is better to just avoid sending payloads in GET requests.
Please don't use body with a get request. The GET request is purely meant to collect back data from server, which allows you to sent Queries, not data on the request. Just remove body:'false' or use body:false. The best way is to remove the body from your request so unexpected input is not sent via this GET request.

Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response when using http get req from JS to SlackAPI

I understand that there are many similar questions, but I am posting this because I feel it is slightly different.
I am trying to send a GET request to the Slack API using an HTTP request.
Specifically, the code looks like the following.
import useSWR from "swr";
const useSlackSearch = (query: string) => {
const token = process.env.NEXT_PUBLIC_SLACK_API_USER_TOKEN;
const myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer " + token);
const slackURL = `https://slack.com/api/search.messages?query=${query}`;
const fetcher = async (url: string) => {
const response = await fetch(url, {
headers: myHeaders,
}).then((res) => res.json());
return response;
};
const { data, error } = useSWR(slackURL, fetcher, {
revalidateOnFocus: true,
revalidateOnReconnect: true,
});
if (error) {
return console.log(`Failed to load: ${error}`);
} else if (!data) {
return console.log("Loading...");
} else {
console.log(data);
return data;
}
};
export default useSlackSearch;
The environments I'm using are as follows.
Device: MacBook Air
OS: macOS
Browser: Chrome
From: localhost:3000
To: Slack API html page (https://slack.com/api/search.messages)
After reading the MDN articles like below, I understood that
There is such a thing as a simple HTTP request as defined by MDN
If the request you want to send does not correspond to this simple request, the browser will send a preflight request
In the response to that preflight request, there is a header called Access-Control-Allow-Headers.
Only headers set to the value of this Access-Control-Allow-Headers header can be used as headers in the main request after preflighting.
In this case, I tried to use the Authorization header, but it was trapped by the above restriction.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
That's all I understand.
However, on the official Slack API page for the method in question, it says to specify the token in the Authorization header, so I'm having trouble.
I also don't understand how to specify the Access-Control-Request-Headers in the preflight header, as described in another questioner's thread. The reason is that the only thing that communicates to the Slack API is the browser in this case, and the only relevant source is JavaScript (React / Next.js to be exact)!
After that, I found preflight response from Slack API as follows;
access-control-allow-headers: slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags
As I thought, I understand that Authorization is not allowed because it is not included as a value. So the question is how to solve it.
Furthermore, I found out later that the preflight request from the browser properly declared that it wanted to use Authorization as an actual request header. However, the preflight response did not contain the value.
Following CBroe's advice, I was able to contact the Slack help center directly, so I asked this problem. What I found out as a result is that HTTP requests from browsers are not supported as of the end of February 2022. Of course, they have received quite a lot of requests regarding this, so they hope to address it at some point.
This time, the browser sent Access-Control-Request-Headers:Authorization in the preflight request. But the Slack API server side did not allow the Authorization header in the request from the browser. Therefore, Authorization was not set in the Access-Control-Allow-Headers in the preflight response from the Slack API side.
As a result, the response from the Slack API side returned Invalid Auth, even though Authorization was added as a header when making an actual request from the browser.
Through this error, I gained a deeper understanding of HTTP requests such as CORS and preflighting, but since it is not explicitly written on the official Slack website, I left it here.
What is Preflight: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
What is Access-Control-Allow-Header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
What is CORS simple request: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
I could not get the Authorization header to work either. However, Slack provided this example for adding token authentication to the Post body following the deprecation of the query parameters method.
This worked for me to make Web API calls to Slack from the browser (for testing) so that Slack would read the token for authentication. Note, according to Slack's best practices for security, user and bot tokens should be stored with care and not used in client-side Javascript:
try {
const res = await fetch("https://slack.com/api/conversations.list", {
method: "POST",
body: `token=${TOKEN}`, // body data type must match "Content-Type" header
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}).catch((error) => {
console.log(error);
});
if (!res.ok) {
throw new Error(`Server error ${res.status}`);
} else {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.log(error);
}
using token in request body instead of Authorization header worked for me.
axios({
method: 'post',
url: 'https://slack.com/api/chat.postMessage',
data: `text=Hi&channel=D048GGYTJUK&token=${process.env.TOKEN}`
})

Error 400 receieved when fetching from trovo API

I've been granted acces to an API that uses OAuth 2, I've tried it with different API's and my requests were working.
However with the trovo API I seem to get error 400 at every endpoint.
I also get a "blocked by CORS policy: o 'Access-Control-Allow-Origin' header is present on the requested resource."
function fetching() {
fetch("https://open-api.trovo.live/openplatform/validate", {
"method": "GET",
"headers": {
"Accept": "application/json",
"Authorization": "myKey",
"Client-Id": "myID"
}
})
.then(response => {
console.log(response.json());
})
.catch(err => {
console.error(err);
});
}
I also recieved a Client Secret not sure what to do with that.
Here is the documentation from Trovo: https://developer.trovo.live/docs/APIs.html
Altogether I'm quite new to working with API's.
The OAuth flow requires a server, and cannot be done entirely on the front-end. In this example, you would need a server running somewhere other than StreamElements that would keep track of the access and refresh token.
You would then have the front end connect to the server to get the access token instead of directly to Trovo. Reason for this: security. To get the access token you need the private key, and you don't want to be sending that to the front end, or else they can do stuff as if they were you.
Even though stream overlays don't seem like a front end, it's most often just a browser being rendered, as if you just had a website open in chrome.
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
https://www.youtube.com/watch?v=3pZ3Nh8tgTE

Getting CORS error on Active Directory plugin for React App

I am trying to integrate Active Directory ADAL plugin within my Reactjs app but I am getting CORS error when fetching results.
I was following React ADAL package steps till I found a SO question which helped me a lot, but still I am getting a CORS error while fetching Dynamics CRM data.
This is part of my MyComponent component:
import React, { Component } from 'react';
import { adalApiFetch } from '../../../adalConfig';
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = { APIResponse: '' };
this.getLeads = this.getLeads.bind(this);
}
componentDidMount() {
this.getLeads();
}
getLeads() {
let result;
/*(async () => {
let response = await fetch('https://myorg.api.crm.dynamics.com/api/data/v9.1/leads');
let data = await response.json();
console.log(data);
})();
fetch('https://myorg.api.crm.dynamics/api/data/v9.1/leads')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => console.error('SERVER ERROR:', error));*/
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
mode: 'cors'
};
adalApiFetch(fetch, 'https://myorg.api.crm.dynamics/api/', options)
.then(response => response.json())
.then(data => {
this.setState(Object.assign(this.state, { APIResponse: data }));
console.log(data);
}).catch(error => console.error('SERVER ERROR:', error));
}
render() {
return (
<div>
<h2>My Component</h2>
</div>
);
}
}
export default MyComponent;
I kept the comments in case you suggest me to make the fetch request with the ES7 approach instead of the ES5/6.
I am getting this error on the DevTools:
Access to fetch at 'https://login.microsoftonline.com//oauth2/authorize?client_id=0&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%-SNnykyS3kfmCGv0ar3tRJMn0XvPSwEAAAABBBBBCS5yZWRpcmVgdClodHRwczovL25ld2NvMi5hcGkuY3JtMi5keW5hbWljcy5jb20vYXBpLw%26RedirectTo%3dhttps%253a%252f%252fmyorg.api.crm2.dynamics.com%252f&nonce=636848908126477531.RGFhOTkxMzQtqDRlYy00Nzk3LThkZDgtZjk5MjA5MDM3Nzk5MWQyMTE4OWQtODNjMy00YzhhLTk2YjMtMzY4MmQ0MzFkZjU5&redirect_uri=https%3a%2f%2fcloudredirector.crm2.dynamics.com%3a443%2fG%2fAuthRedirect%2fIndex.aspx&max_age=86400' (redirected from 'https://myorg.api.crm2.dynamics.com/api/') from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Server error:
index.js:1446 SERVER ERROR: TypeError: Failed to fetch
Any ideas on what is wrong here? Thanks in advance.
This is a CORS issue. CORS stands for Cross Origin Resource Sharing. CORS is a security feature implemented by your browsers.
The browser is going to see that some Javascript request has tried to initiate a request to a different domain than what the browsers is currently at.
Because of this our browser is going to be suspicious, this behavior can not be changed, its hard coded in every browser.
Before the browser attempts to make the request the browser itself is going to do a initial request to the api(aka preflight). Kinda like:
"Hey API, I'm trying to make a request over do you. The request is coming from a website at some-domain.com, it seems strange, what do you think?"
The API has the option to either allow or disallow the request.
In your case, the API response:
"Hey browser, I agreed with you, this seems strange. You should only allow this request if your coming from the-other-domain.com"
The API response then goes back to the browser. And then the browser says back
"Hey you know what, the server says that you can not make a request over to them at while your at some-domain.com. Sorry Javascript code we're not allowed to do that."
That is what is happening in your application now. The browser is going to check if there's a different domain, subdomain or port. If any of these things are different, the CORS kicks in. In your case your probably at localhost:XXX and you're making a request to https://myorg.api.crm.dynamics/api/
A thing to keep in mind is this is a Browser security. If you make this request form e.g Postman or CURL at the Terminal. Postman says:
"You know what, I don't care if you make a request to a different API. Im not the browser and you can do anything you want."
Postman and similar applications don't have CORS stuff so they don't care.
That's whats going on to answer your question.

Unable to make LinkedIn API calls from localhost with Axios

I am trying to access linkedin profile using axios get request, which doesn't work on localhost and I get the following error
XMLHttpRequest cannot load
https://api.linkedin.com/v1/people/~:(id,email-address)?format=json.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8030' is therefore not allowed
access. The response had HTTP status code 401.
I am able to get access-token using react-linkedin-login package, after getting the access token I am trying the following code
var linkedInUrl = `https://api.linkedin.com/v1/people/~:(id,email-address)?format=json`;
var headers = {
'Authorization': `Bearer ${accessToken}`,
'Access-Control-Allow-Methods':'GET,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin':'*',
'Access-Control-Request-Headers':'Origin, X-Requested-With, Content-Type, Accept',
'Content-Type':'application/x-www-form-urlencoded'
};
return (dispatch) => {
axios.get(linkedInUrl, {headers}).then(({data}) => {
console.log(data);
}, (error) => {
console.log(error);
});
}
The problems lies in linkedin server how it takes request I guess, it doesn't allow localhost to make call I think. How to overcome this to actually develop the service before I deploy and run on server.
Thanks for helping..
This is because of a browser restriction called the "Same-origin Policy", which prevents fetching data from, or posting data to, URLs that are part of other domains. You can get around it if the other domain supports Cross-origin Resource Sharing (CORS), but it looks like LinkedIn doesn't, so you may have trouble.
One way around this is to have a web service which can proxy your request to LinkedIn - there's no domain restrictions there.
https://en.wikipedia.org/wiki/Same-origin_policy
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
try jsonp for CORS request - reference - axios cookbook
var jsonp = require('jsonp');
jsonp(linkedInUrl, null, function (err, data) {
if (err) {
console.error(err.message);
} else {
console.log(data);
}
});
EDIT
Use jQuery to perform JSONP request and to set headers
$.ajax({url: linkedInUrl,
type: 'GET',
contentType: "application/json",
headers: header, /* pass your header object */
dataType: 'jsonp',
success: function(data) {
console.log(data);
},
error: function(err) {
console.log('Error', err);
},
});
https://cors-anywhere.herokuapp.com/ - Add this before the url and it will work

Categories